SpringBoot原理以及多数据源使用探究

本文详细介绍了SpringBoot中事务配置的方法,包括数据源配置、sqlSessionFactory配置、MapperScannerConfigurer配置及事务管理器配置等关键步骤,并展示了如何实现多数据源的支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

最近微服务很热,而SpringBoot以轻量级和内嵌tomcat,方便启动调试为微服务越来越被采用,而现在前言的技术的demo一般都也使用SpringBoot编写,所以与必要研究下SpringBoot原理。

二、启动

启动时序图

0?wx_fmt=png

上面流程启动从SpringApplication的run方法开始,到解析application.properties结束。

三、创建应用程序上下文和嵌入式tomcat

上面配置文件解析完毕后紧接着就是创建应用程序上下文

0?wx_fmt=png

四、ConfigurationProperties Bean的创建

SpringBoot中不建议使用XML配置,所以比较常用的是使用ConfigurationProperties注解创建bean从application.properties中加载配置项。

@ConfigurationProperties(prefix = "mysql")public class MySqlProperties {    private String driverClassName;    private String url;    public String getDriverClassName() {        return driverClassName;
    }    public void setDriverClassName(String driverClassName) {        this.driverClassName = driverClassName;
    }    public String getUrl() {        return url;
    }    public void setUrl(String url) {        this.url = url;
    }    public String getUserName() {        return userName;
    }    public void setUserName(String userName) {        this.userName = userName;
    }    public String getPassWord() {        return passWord;
    }    public void setPassWord(String passWord) {        this.passWord = passWord;
    }    private String userName;    private String passWord;

}

而application.properties中配置为:
mysql.passWord =

0?wx_fmt=png

五、 事务配置

Spring中使用XML配置的事务管理,那么springboot中如何进行配置对应的东西那?

5.1 SpringBoot中 DataSource的配置

首先数据源属性Bean

@ConfigurationProperties(prefix = "mysql")public class MySqlProperties {    private String driverClassName;    private String url;    public String getDriverClassName() {        return driverClassName;
    }    public void setDriverClassName(String driverClassName) {        this.driverClassName = driverClassName;
    }    public String getUrl() {        return url;
    }    public void setUrl(String url) {        this.url = url;
    }    public String getUserName() {        return userName;
    }    public void setUserName(String userName) {        this.userName = userName;
    }    public String getPassWord() {        return passWord;
    }    public void setPassWord(String passWord) {        this.passWord = passWord;
    }    private String userName;    private String passWord;

}

然后创建DataSource的bean

@Configuration@EnableConfigurationProperties(MySqlProperties.class)@ConditionalOnClass(TDataSource.class)@AutoConfigureBefore(DataSourceAutoConfiguration.class)// 三、设置扫描器@MapperScan(basePackages = "com.zlx.demo.web.speech2.mapper", sqlSessionFactoryRef = "sqlSessionFactory1")public class MysqlAutoConfiguration {    @Autowired
    private MySqlProperties properties;    // 一、创建数据源
    @Primary
    @Bean(name = "dataSource")    public DataSource dataSource() throws TddlException {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(properties.getDriverClassName());
        dataSource.setUrl(properties.getUrl());
        dataSource.setUsername(properties.getUserName());
        dataSource.setPassword(properties.getPassWord());        return dataSource;
    }
}

5.2 SpringBoot中 sqlSessionFactory的配置

Spring中XML配置知道要创建个sqlSessionFactory对象并且要进行属性配置,所以下面首先讲下mybaits的属性配置:

@ConfigurationProperties(prefix="mybatis")public class MybatisProperties{  public static final String MYBATIS_PREFIX = "mybatis";  private String configLocation;  private String[] mapperLocations;  private String typeAliasesPackage;  private String typeHandlersPackage;  private boolean checkConfigLocation = false;  private ExecutorType executorType;  private Properties configurationProperties;  @NestedConfigurationProperty
  private Configuration configuration;  public String getConfigLocation()
  {    return this.configLocation;
  }  public void setConfigLocation(String configLocation)
  {    this.configLocation = configLocation;
  }  @Deprecated
  public String getConfig()
  {    return this.configLocation;
  }  @Deprecated
  public void setConfig(String config)
  {    this.configLocation = config;
  }  public String[] getMapperLocations()
  {    return this.mapperLocations;
  }  public void setMapperLocations(String[] mapperLocations)
  {    this.mapperLocations = mapperLocations;
  }  public String getTypeHandlersPackage()
  {    return this.typeHandlersPackage;
  }  public void setTypeHandlersPackage(String typeHandlersPackage)
  {    this.typeHandlersPackage = typeHandlersPackage;
  }  public String getTypeAliasesPackage()
  {    return this.typeAliasesPackage;
  }  public void setTypeAliasesPackage(String typeAliasesPackage)
  {    this.typeAliasesPackage = typeAliasesPackage;
  }  public boolean isCheckConfigLocation()
  {    return this.checkConfigLocation;
  }  public void setCheckConfigLocation(boolean checkConfigLocation)
  {    this.checkConfigLocation = checkConfigLocation;
  }  public ExecutorType getExecutorType()
  {    return this.executorType;
  }  public void setExecutorType(ExecutorType executorType)
  {    this.executorType = executorType;
  }  public Properties getConfigurationProperties()
  {    return this.configurationProperties;
  }  public void setConfigurationProperties(Properties configurationProperties)
  {    this.configurationProperties = configurationProperties;
  }  public Configuration getConfiguration()
  {    return this.configuration;
  }  public void setConfiguration(Configuration configuration)
  {    this.configuration = configuration;
  }  public Resource[] resolveMapperLocations()
  {
    ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
    List<Resource> resources = new ArrayList();    if (this.mapperLocations != null) {      for (String mapperLocation : this.mapperLocations) {        try
        {
          Resource[] mappers = resourceResolver.getResources(mapperLocation);
          resources.addAll(Arrays.asList(mappers));
        }        catch (IOException localIOException) {}
      }
    }    return (Resource[])resources.toArray(new Resource[resources.size()]);
  }
}

同样这些配置想从application.properties中进行配置,

@Configuration@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})@ConditionalOnBean({DataSource.class})@EnableConfigurationProperties({MybatisProperties.class})@AutoConfigureAfter({DataSourceAutoConfiguration.class})public class MybatisAutoConfiguration{  private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);  private final MybatisProperties properties;  private final Interceptor[] interceptors;  private final ResourceLoader resourceLoader;  private final DatabaseIdProvider databaseIdProvider;  public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider)
  {    this.properties = properties;    this.interceptors = ((Interceptor[])interceptorsProvider.getIfAvailable());    this.resourceLoader = resourceLoader;    this.databaseIdProvider = ((DatabaseIdProvider)databaseIdProvider.getIfAvailable());
  }  @PostConstruct
  public void checkConfigFileExists()
  {    if ((this.properties.isCheckConfigLocation()) && (StringUtils.hasText(this.properties.getConfigLocation())))
    {
      Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
      Assert.state(resource.exists(), "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");
    }
  }  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource)
    throws Exception  {
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setVfs(SpringBootVFS.class);    if (StringUtils.hasText(this.properties.getConfigLocation())) {
      factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
    }
    factory.setConfiguration(this.properties.getConfiguration());    if (this.properties.getConfigurationProperties() != null) {
      factory.setConfigurationProperties(this.properties.getConfigurationProperties());
    }    if (!ObjectUtils.isEmpty(this.interceptors)) {
      factory.setPlugins(this.interceptors);
    }    if (this.databaseIdProvider != null) {
      factory.setDatabaseIdProvider(this.databaseIdProvider);
    }    if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
      factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
    }    if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
      factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
    }    if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }    return factory.getObject();
  }  @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory)
  {
    ExecutorType executorType = this.properties.getExecutorType();    if (executorType != null) {      return new SqlSessionTemplate(sqlSessionFactory, executorType);
    }    return new SqlSessionTemplate(sqlSessionFactory);
  }  public static class AutoConfiguredMapperScannerRegistrar
    implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware
  {    private BeanFactory beanFactory;    private ResourceLoader resourceLoader;    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
    {
      MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");

      ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);      try
      {        if (this.resourceLoader != null) {
          scanner.setResourceLoader(this.resourceLoader);
        }
        List<String> packages = AutoConfigurationPackages.get(this.beanFactory);        if (MybatisAutoConfiguration.logger.isDebugEnabled()) {          for (String pkg : packages) {
            MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
          }
        }
        scanner.setAnnotationClass(Mapper.class);
        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(packages));
      }      catch (IllegalStateException ex)
      {
        MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.", ex);
      }
    }    public void setBeanFactory(BeanFactory beanFactory)
      throws BeansException    {      this.beanFactory = beanFactory;
    }    public void setResourceLoader(ResourceLoader resourceLoader)
    {      this.resourceLoader = resourceLoader;
    }
  }  @Configuration
  @Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})  @ConditionalOnMissingBean({MapperFactoryBean.class})  public static class MapperScannerRegistrarNotFoundConfiguration
  {    @PostConstruct
    public void afterPropertiesSet()
    {
      MybatisAutoConfiguration.logger.debug("No {} found.", MapperFactoryBean.class.getName());
    }
  }
}

如果自己没有注入的话,springboot会通过上面代码进入注入,其中注解 @ConditionalOnMissingBean

    @Bean(name = "sqlSessionFactory1")    @Primary
    public SqlSessionFactory sqlSessionFactoryBean1() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();

        sqlSessionFactoryBean.setDataSource(dataSource1());
        sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations(new String[]{"classpath:mapper/*.xml"}));        return sqlSessionFactoryBean.getObject();
    }    public Resource[] resolveMapperLocations(String[] mapperLocations) {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList();        if (mapperLocations != null) {            for (String mapperLocation : mapperLocations) {                try {
                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
                    resources.addAll(Arrays.asList(mappers));
                } catch (IOException localIOException) {
                }
            }
        }        return (Resource[]) resources.toArray(new Resource[resources.size()]);
    }

5.3 SpringBoot中MapperScannerConfigurer配置

Spring中XML配置知道这个主要是配置扫描mapper路径然后生成数据库操作代理类,那么在SpringBoot中只需要一个简单的注解:0?wx_fmt=png

5.4 SpringBoot中事务管理器配置

Spring中XML配置知道有注解式和xml配置式,SpringBoot不推荐XML配置,所有讲下注解。之前xml开启事务管理器需要创建DataSourceTransactionManager对象,现在Springboot中只需要:0?wx_fmt=png0?wx_fmt=png

5.4.1 SpringBoot中多数据源使用

@EnableTransactionManagement@RestController@SpringBootApplicationpublic class DemoApp implements TransactionManagementConfigurer{    @RequestMapping("/")    String home() {        return "Hello Demo!";
    }    @Resource(name="txManager1")    private PlatformTransactionManager txManager1;    // 实现接口 TransactionManagementConfigurer 方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {        return txManager1;
    }    @Bean
    public StartRunner startRunner(){        return new StartRunner();
    }    public static void main( String[] args )
    {
        SpringApplication.run(DemoApp.class, args);
    }
}

数据源一配置:

//三、设置扫描器// 三、设置扫描器@MapperScan(basePackages = "com.zlx.demo.web.speech2.mapper", sqlSessionFactoryRef = "sqlSessionFactory1")public class MysqlAutoConfiguration {    @Autowired
    private MySqlProperties properties;    // 一、创建数据源
    @Primary
    @Bean(name = "dataSource1")    public DataSource dataSource1() throws TddlException {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(properties.getDriverClassName());
        dataSource.setUrl(properties.getUrl());
        dataSource.setUsername(properties.getUserName());
        dataSource.setPassword(properties.getPassWord());        return dataSource;
    }    // 二、创建SqlSessionFactory
    @Bean(name = "sqlSessionFactory1")    @Primary
    public SqlSessionFactory sqlSessionFactoryBean1() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();

        sqlSessionFactoryBean.setDataSource(dataSource1());
        sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations(new String[] { "classpath:mapper/*.xml" }));        return sqlSessionFactoryBean.getObject();
    }    // 四、 创建事务管理器
    @Bean(name = "txManager1")    @Primary
    public PlatformTransactionManager txManager1(@Qualifier("dataSource1") DataSource dataSource) {

        System.out.println("-----------dataource-----" + dataSource.toString());        return new DataSourceTransactionManager(dataSource);
    }    // 创建SqlSessionTemplate
    @Bean("sqlSessionTemplate1")    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
        System.out.println("-----------sqlSessionFactory-----" + sqlSessionFactory.toString());        return new SqlSessionTemplate(sqlSessionFactory);
    }    public Resource[] resolveMapperLocations(String[] mapperLocations) {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList();        if (mapperLocations != null) {            for (String mapperLocation : mapperLocations) {                try {
                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
                    resources.addAll(Arrays.asList(mappers));
                } catch (IOException localIOException) {
                }
            }
        }        return (Resource[]) resources.toArray(new Resource[resources.size()]);
    }

数据源二配置:

//三、设置扫描器
@MapperScan(basePackages = "com.zlx.demo.web.business.mapper", sqlSessionFactoryRef = "sqlSessionFactory1")
public class MysqlAutoConfiguration2 {

    @Autowired
    private MySqlProperties properties;

    // 一、创建数据源
    @Primary
    @Bean(name = "dataSource2")
    public DataSource dataSource1() throws TddlException {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(properties.getDriverClassName());
        dataSource.setUrl(properties.getUrl());
        dataSource.setUsername(properties.getUserName());
        dataSource.setPassword(properties.getPassWord());
        return dataSource;
    }

    // 二、创建SqlSessionFactory
    @Bean(name = "sqlSessionFactory2")
    @Primary
    public SqlSessionFactory sqlSessionFactoryBean1() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();

        sqlSessionFactoryBean.setDataSource(dataSource1());
        sqlSessionFactoryBean.setMapperLocations(resolveMapperLocations(new String[] { "classpath:mapper/*.xml" }));

        return sqlSessionFactoryBean.getObject();
    }

    // 四、 创建事务管理器
    @Bean(name = "txManager2")
    @Primary
    public PlatformTransactionManager txManager1(@Qualifier("dataSource1") DataSource dataSource) {

        System.out.println("-----------dataource-----" + dataSource.toString());
        return new DataSourceTransactionManager(dataSource);
    }

    // 创建SqlSessionTemplate
    @Bean("sqlSessionTemplate2")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
        System.out.println("-----------sqlSessionFactory-----" + sqlSessionFactory.toString());

        return new SqlSessionTemplate(sqlSessionFactory);
    }

    public Resource[] resolveMapperLocations(String[] mapperLocations) {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList();
        if (mapperLocations != null) {
            for (String mapperLocation : mapperLocations) {
                try {
                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
                    resources.addAll(Arrays.asList(mappers));
                } catch (IOException localIOException) {
                }
            }
        }
        return (Resource[]) resources.toArray(new Resource[resources.size()]);
    }

另外SqlSessionTemplate是对SqlSessionFactory的一个包装,这里每个数据源也配置了一个,如果想使用它的话,只需要修改@mapperscan,设置sqlSessionTemplateRef替换sqlSessionFactoryRef

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值