前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot使用及原理浅尝

SpringBoot使用及原理浅尝

作者头像
加多
发布2018-09-06 15:12:21
2.9K0
发布2018-09-06 15:12:21
举报
文章被收录于专栏:Java编程技术Java编程技术

一、前言

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

二、启动

启动时序图

解析配置文件.png

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

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

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

创建spring容器和tomcat.png

四、ConfigurationProperties Bean的创建

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

代码语言:javascript
复制
@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.driverClassName = com.mysql.jdbc.Driver mysql.url = jdbc:mysql://localhost:3306/users mysql.userName = *** mysql.passWord = ***

screenshot.png

五、 事务配置

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

5.1 SpringBoot中 DataSource的配置

首先数据源属性Bean

代码语言:javascript
复制
@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

代码语言:javascript
复制
@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的属性配置:

代码语言:javascript
复制
@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中进行配置, 然后创建sqlsessionfactory的代码:

代码语言:javascript
复制
@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 说明IOC中不存在该类别bean的时候才创建。如果我们需要自己创建则如下代码:

代码语言:javascript
复制
    @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中只需要一个简单的注解:

image.png

5.4 SpringBoot中事务管理器配置

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

image.png

然后只需要在需要进行事务管理的bo上面加上@Transactional即可,很方便的有没有-

screenshot.png

5.4.1 SpringBoot中多数据源使用

代码语言:javascript
复制
@EnableTransactionManagement
@RestController
@SpringBootApplication
public 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);
    }
}

数据源一配置:

代码语言:javascript
复制
//三、设置扫描器
// 三、设置扫描器
@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()]);
    }

数据源二配置:

代码语言:javascript
复制
//三、设置扫描器
@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

六、总结

SpringBoot简化了开发,节省了时间,是未来的趋势,但是对其原理也要知其然也要知其所以然。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.01.06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、启动
  • 三、创建应用程序上下文和嵌入式tomcat
  • 四、ConfigurationProperties Bean的创建
  • 五、 事务配置
    • 5.1 SpringBoot中 DataSource的配置
      • 5.2 SpringBoot中 sqlSessionFactory的配置
        • 5.3 SpringBoot中MapperScannerConfigurer配置
          • 5.4 SpringBoot中事务管理器配置
            • 5.4.1 SpringBoot中多数据源使用
        • 六、总结
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档