zoukankan      html  css  js  c++  java
  • 【源码解析】自动配置的这些细节都不知道,别说你会 springboot

    spring-boot 相对于 spring,很重要的一个特点就是自动配置,使约定大于配置思想成功落地。xxx-spring-boot-starter 一系列引导器能够开箱即用,或者只需要很少的配置(对于初学人员)就是因为已做了默认的自动配置。

    自动配置在一开始就初始化了一些配置,同时提供修改配置的入口。

    整体结构

    spring-boot-autoconfigure 包是 spring-boot-starter 中一个非常重要的包,其中提供了自动配置功能,还对常用依赖,设置了默认配置。

    依赖

    其依赖的包有三种:

    • 基础包:spring-boot
    • 可选功能依赖包:提供默认配置的常用依赖包,实际使用时由使用者提供
    • 测试包

    可选功能依赖包有 spring-data-redis、validator、thymeleaf、websocket 等等。下面会选几个作为示例具体讲解。

    原理

    @EnableAutoConfiguration

    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
      /**
       *  当此名对应属性为 true 时,才开启自动配置
       */
      String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
      
      /**
       *  需要排除的类(通常当此类在类路径下时使用)
       */
      Class<?>[] exclude() default {};
    
      /**
       *  需要排除的类名(当此类不在类路径下时使用)
       */
      String[] excludeName() default {};
    }
    

    @AutoConfigurationPackage

    将使用此注解的类所属于的包注册成 spring bean。
    此 spring bean 的 beanName 为 AutoConfigurationPackages,
    beanClass 为 BasePackages。

    AutoConfigurationImportSelector

    自动配置选择器,选择哪些类自动配置。

    selectImports

    核心方法:String[] selectImports(AnnotationMetadata annotationMetadata) ,此方法返回需要自动配置的全类名数组。
    需要自动配置的类满足以下条件:

    1. META-INF/spring.factories 中 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的类
    2. @EnableAutoConfiguration 注解中 exclude 、 excludeName 属性代表的类, 配置中 spring.autoconfigure.exclude 中设置的类(若类路径中存在,但是步骤 1 不存在,则抛异常)
    3. 满足包含三种注解的条件:OnBeanCondition(如:ConditionalOnBean、ConditionalOnMissingBean) 、OnClassCondition (如:ConditionalOnClass、ConditionalOnMissingClass)、OnWebApplicationCondition(如:ConditionalOnWebApplication、ConditionalOnNotWebApplication)

    最后,会激活 AutoConfigurationImportEvent 事件。

    getImportGroup 与 DeferredImportSelector.Group

    对来自不同 ImportSelector 的结果进行分组

    自动配置的顺序

    • AutoConfigurationSorter
    • @AutoConfigureOrder
    • @AutoConfigureBefore
    • @AutoConfigureAfter

    AutoConfigurationSorter 是具体控制排序的逻辑
    @AutoConfigureOrder@Order 的 Auto-configuration 特定变体,因此需要制定自定配置的顺序时,可以用 @AutoConfigureOrder 。控制应用配置类的绝对顺序
    @AutoConfigureBefore@AutoConfigureAfter 控制应用配置类的相对顺序。

    具体培训顺序如下:

    1. 根据类名按照字母表递增排序
    2. 根据 @AutoConfigureOrder value 值(默认:0)递增排序
    3. 根据 @AutoConfigureBefore@AutoConfigureAfter 调整排序

    那么 @Order 还能控制自动配置类的顺序吗?

    @SpringBootApplication

    2.1.8.RELEASE 版本中,此注解的组合注解如下:

    // 省略不需关心的注解
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    

    已有原来的 @Configuration 改为 @SpringBootConfiguration,其意义如下:

    • 相当于是 @Configuration 类
    • 使用该注解的类提供 Spring Boot 应用。
      一个应用只能包含一个 @SpringBootConfiguration 类,通常使用 @SpringBootApplication 就可以了

    AbstractDependsOnBeanFactoryPostProcessor

    此类实现 BeanFactoryPostProcessor,会在 spring-boot 启动过程中在合适的时机执行
    继承此类,通过构造器动态决定指定类型的 bean 应该依赖于哪些 bean。

    BackgroundPreinitializer

    此类实现 ApplicationListener<SpringApplicationEvent>
    此类功能为:在耗时任务的后台线程中触发早期初始化,如:
    ValidationInitializerMessageConverterInitializerJacksonInitializerCharsetInitializerConversionServiceInitializerMBeanFactoryInitializer

    @ImportAutoConfiguration

    导入自动配置类。从源码来看,都是测试时用于自动配置。使用此类的注解,也在 META-INF/spring.factories 中配置,示例如下:

    @ImportAutoConfiguration
    public @interface AutoConfigureDataJpa {}
    
    org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa=
    org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,
    org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,
    org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,
    org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
    

    因此使用注解 AutoConfigureDataJpa 就相当于导入了 JpaRepositoriesAutoConfiguration、DataSourceAutoConfiguration 等类。

    使用如下:

    @BootstrapWith(DataJpaTestContextBootstrapper.class)
    @ExtendWith(SpringExtension.class)
    @OverrideAutoConfiguration(enabled = false)
    @TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
    @Transactional
    @AutoConfigureCache
    @AutoConfigureDataJpa
    @AutoConfigureTestDatabase
    @AutoConfigureTestEntityManager
    @ImportAutoConfiguration
    public @interface DataJpaTest {
      // ...
    }
    
    @RunWith(SpringRunner.class)
    @DataJpaTest
    @TestPropertySource(properties = "spring.jpa.hibernate.use-new-id-generator-mappings=false")
    public class DataJpaTestIntegrationTests {
    
    	@Autowired
    	private TestEntityManager entities;
    
    	@Autowired
    	private JdbcTemplate jdbcTemplate;
    
    	@Autowired
    	private ExampleRepository repository;
    
    	@Autowired
    	private DataSource dataSource;
    
    	@Autowired
    	private ApplicationContext applicationContext;
    
    	@Test
    	public void testEntityManager() {
    		ExampleEntity entity = this.entities.persist(new ExampleEntity("spring", "123"));
    		this.entities.flush();
    		Object id = this.entities.getId(entity);
    		ExampleEntity found = this.entities.find(ExampleEntity.class, id);
    		assertThat(found.getName()).isEqualTo("spring");
    	}
        
        // ...
    

    对常用工具的支持

    以上原理是提供自动配置的基石,但实际在使用的时候,很多内容不需要任何(或极少量)配置就能直接使用,一方面是各 xxx-spring-boot-starter 中包含了 spring-boot-autoconfigure 并写了自动配置逻辑,一方面,是 spring-boot 官方在 spring-boot-autoconfigure 包中已经直接支持了。
    spring-boot 对常用工具的支持
    spring-boot 对常用数据源的支持

    示例:gson 自动配置

    支持有如下类:

    • GsonProperties
    • GsonBuilderCustomizer
    • GsonAutoConfiguration

    GsonProperties 类获取 Gson 的配置属性

    @ConfigurationProperties(prefix = "spring.gson")
    public class GsonProperties {
      private Boolean generateNonExecutableJson;
      private Boolean excludeFieldsWithoutExposeAnnotation;
      private Boolean serializeNulls;
      private String dateFormat;
      // ...
    }
    
    @FunctionalInterface
    public interface GsonBuilderCustomizer {
    	/**
    	 * 自定义 GsonBuilder
    	 */
    	void customize(GsonBuilder gsonBuilder);
    }
    

    GsonAutoConfiguration 中使用 GsonProperties 和 GsonBuilderCustomizer(内部类中实现)

    @Configuration
    @ConditionalOnClass(Gson.class)
    @EnableConfigurationProperties(GsonProperties.class)
    public class GsonAutoConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {
            GsonBuilder builder = new GsonBuilder();
            customizers.forEach((c) -> c.customize(builder));
            return builder;
        }
    
        @Bean
        @ConditionalOnMissingBean
        public Gson gson(GsonBuilder gsonBuilder) {
            return gsonBuilder.create();
        }
    
        @Bean
        public StandardGsonBuilderCustomizer standardGsonBuilderCustomizer(GsonProperties gsonProperties) {
            return new StandardGsonBuilderCustomizer(gsonProperties);
        }
    
        static final class StandardGsonBuilderCustomizer implements GsonBuilderCustomizer, Ordered {
    
            private final GsonProperties properties;
    
            StandardGsonBuilderCustomizer(GsonProperties properties) {
                this.properties = properties;
            }
    
            @Override
            public int getOrder() {
                return 0;
            }
    
            @Override
            public void customize(GsonBuilder builder) {
             // ...
            }
    

    公众号:逸飞兮(专注于 Java 领域知识的深入学习,从源码到原理,系统有序的学习)

    逸飞兮

  • 相关阅读:
    HDU 2888 Check Corners (模板题)【二维RMQ】
    POJ 3264 Balanced Lineup(模板题)【RMQ】
    poj 3368 Frequent values(经典)【RMQ】
    SPOJ RPLN (模板题)(ST算法)【RMQ】
    UVA 796 Critical Links(模板题)(无向图求桥)
    UVA 315 Network (模板题)(无向图求割点)
    POJ 2029 Get Many Persimmon Trees (模板题)【二维树状数组】
    poj 3067 Japan 【树状数组】
    POJ 2481 Cows 【树状数组】
    POJ 1195 Mobile phones【二维树状数组】
  • 原文地址:https://www.cnblogs.com/lw5946/p/11689890.html
Copyright © 2011-2022 走看看