spring 38 Boot 自动配置

AopAutoConfiguration

Spring Boot 是利用了自动配置类来简化了 aop 相关配置

  • AOP 自动配置类为 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
  • 可以通过 spring.aop.auto=false 禁用 aop 自动配置
  • AOP 自动配置的本质是通过 @EnableAspectJAutoProxy 来开启了自动代理,如果在引导类上自己添加了 @EnableAspectJAutoProxy 那么以自己添加的为准
  • @EnableAspectJAutoProxy 的本质是向容器中添加了 AnnotationAwareAspectJAutoProxyCreator 这个 bean 后处理器,它能够找到容器中所有切面,并为匹配切点的目标类创建代理,创建代理的工作一般是在 bean 的初始化阶段完成的

DataSourceAutoConfiguration

  • 对应的自动配置类为:org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
  • 它内部采用了条件装配,通过检查容器的 bean,以及类路径下的 class,来决定该 @Bean 是否生效

简单说明一下,Spring Boot 支持两大类数据源:

  • EmbeddedDatabase - 内嵌数据库连接池
  • PooledDataSource - 非内嵌数据库连接池

PooledDataSource 又支持如下数据源

  • hikari 提供的 HikariDataSource
  • tomcat-jdbc 提供的 DataSource
  • dbcp2 提供的 BasicDataSource
  • oracle 提供的 PoolDataSourceImpl

如果知道数据源的实现类类型,即指定了 spring.datasource.type,理论上可以支持所有数据源,但这样做的一个最大问题是无法订制每种数据源的详细配置(如最大、最小连接数等)

MybatisAutoConfiguration

  • MyBatis 自动配置类为 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
  • 它主要配置了两个 bean
    • SqlSessionFactory - MyBatis 核心对象,用来创建 SqlSession
    • SqlSessionTemplate - SqlSession 的实现,此实现会与当前线程绑定
    • 用 ImportBeanDefinitionRegistrar 的方式扫描所有标注了 @Mapper 注解的接口
    • 用 AutoConfigurationPackages 来确定扫描的包
  • 还有一个相关的 bean:MybatisProperties,它会读取配置文件中带 mybatis. 前缀的配置项进行定制配置

@MapperScan 注解的作用与 MybatisAutoConfiguration 类似,会注册 MapperScannerConfigurer 有如下区别

  • @MapperScan 扫描具体包(当然也可以配置关注哪个注解)
  • @MapperScan 如果不指定扫描具体包,则会把引导类范围内,所有接口当做 Mapper 接口
  • MybatisAutoConfiguration 关注的是所有标注 @Mapper 注解的接口,会忽略掉非 @Mapper 标注的接口

这里有同学有疑问,之前介绍的都是将具体类交给 Spring 管理,怎么到了 MyBatis 这儿,接口就可以被管理呢?

  • 其实并非将接口交给 Spring 管理,而是每个接口会对应一个 MapperFactoryBean,是后者被 Spring 所管理,接口只是作为 MapperFactoryBean 的一个属性来配置

TransactionAutoConfiguration

  • 事务自动配置类有两个:

    • org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
    • org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
  • 前者配置了 DataSourceTransactionManager 用来执行事务的提交、回滚操作

  • 后者功能上对标 @EnableTransactionManagement,包含以下三个 bean

    • BeanFactoryTransactionAttributeSourceAdvisor 事务切面类,包含通知和切点
    • TransactionInterceptor 事务通知类,由它在目标方法调用前后加入事务操作
    • AnnotationTransactionAttributeSource 会解析 @Transactional 及事务属性,也包含了切点功能
  • 如果自己配置了 DataSourceTransactionManager 或是在引导类加了 @EnableTransactionManagement,则以自己配置的为准

ServletWebServerFactoryAutoConfiguration

  • 提供 ServletWebServerFactory

DispatcherServletAutoConfiguration

  • 提供 DispatcherServlet
  • 提供 DispatcherServletRegistrationBean

WebMvcAutoConfiguration

  • 配置 DispatcherServlet 的各项组件,提供的 bean 见过的有
    • 多项 HandlerMapping
    • 多项 HandlerAdapter
    • HandlerExceptionResolver

ErrorMvcAutoConfiguration

  • 提供的 bean 有 BasicErrorController

MultipartAutoConfiguration

  • 它提供了 org.springframework.web.multipart.support.StandardServletMultipartResolver
  • 该 bean 用来解析 multipart/form-data 格式的数据

HttpEncodingAutoConfiguration

  • POST 请求参数如果有中文,无需特殊设置,这是因为 Spring Boot 已经配置了 org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter
  • 对应配置 server.servlet.encoding.charset=UTF-8,默认就是 UTF-8
  • 当然,它只影响非 json 格式的数据

演示 - 自动配置类原理

关键代码

假设已有第三方的两个自动配置类

@Configuration // ⬅️第三方的配置类
static class AutoConfiguration1 {
    @Bean
    public Bean1 bean1() {
        return new Bean1();
    }
}

@Configuration // ⬅️第三方的配置类
static class AutoConfiguration2 {
    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }
}

提供一个配置文件 META-INF/spring.factories,key 为导入器类名,值为多个自动配置类名,用逗号分隔

MyImportSelector=\
AutoConfiguration1,\
AutoConfiguration2

注意

  • 上述配置文件中 MyImportSelector 与 AutoConfiguration1,AutoConfiguration2 为简洁均省略了包名,自己测试时请将包名根据情况补全
    key 若为内部类用 $ 隔开,值无要求。

引入自动配置

@Configuration // ⬅️本项目的配置类
@Import(MyImportSelector.class)
static class Config { }

static class MyImportSelector implements DeferredImportSelector {
    // ⬇️该方法从 META-INF/spring.factories 读取自动配置类名,返回的 String[] 即为要导入的配置类
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return SpringFactoriesLoader
            .loadFactoryNames(MyImportSelector.class, null).toArray(new String[0]);
    }
}

收获💡

  1. 自动配置类本质上就是一个配置类而已,只是用 META-INF/spring.factories 管理,与应用配置类解耦
  2. @Enable 打头的注解本质是利用了 @Import
  3. @Import 配合 DeferredImportSelector 即可实现导入,selectImports 方法的返回值即为要导入的配置类名
  4. DeferredImportSelector 的导入会在最后执行,为的是让其它配置优先解析
posted @ 2022-07-15 22:48  xy7112  阅读(106)  评论(0)    收藏  举报