• SpringBoot自动配置的魔法


    Spring自动配置

    从@SpringBootApplication注解说起

    SpringBoot会根据类路径下的类自动配置,省去了编写繁琐的xml配置文件。原本基于xml配置bean的方式编程基于Java代码,并且可以条件化配置,根据不同的场景配置也随之不同。是不是很智能

    为了清楚SpringBoot自动配置的原理,我们从最简单的SpringBoot的启动类说起,看一个简单的启动实例

    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class);
        }
    }
    

    SpringBoot应用的启动很简单,就是一个main方法,然后执行SpringApplication的run方法。先不关心run方法是怎么执行的。我们先看SpringBoot应用的核心注解@SpringBootApplication

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = {
    		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    	.....
    }
    

    查看该注解的源代码可知,这是一个组合注解。

    分别查看每个注解的含义

    @SpringBootConfiguration

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public @interface SpringBootConfiguration {
    }
    
    

    可知该注解就是@Configuration注解,该注解什么这个一个配置类,在SpringBoot中很常见。

    @CompontScan注解指定哪些包扫描或者不扫描。

    使SpringBoot应用拥有自动配置魔法的注解是@EnableAutoConfiguraion。该注解可以让SpringBoot根据类路径中的依赖为当前项目进行自动配置 ,所以SpringBoot可以自动配置主要是因为SpringBoot应用上的@EnableAutoConfiguraion注解来实现的,所以在启动类上加入该注解,就会开启自动配置。

    那么,这个注解是如何实现自动化配置的呢。接下来我们要一探究竟。

    自动配置背后的注解

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    	.....
    }
    

    该注解也是一个组合注解,这里有一个@Import(AutoConfigurationImportSelector.class),那么@Import注解的作用是什么呢,查看@Import的源码注释,写着Indicates one or more {@link Configuration @Configuration} classes to import.Provides functionality equivalent to the {@code <import/>} element in Spring XML.,注释表明这个注解指明了要导入的配置类,在功能上和Spring XML配置中的<import>相同

    那这里@Import导入的一个AutoConfigurationImportSelector又什么作用呢?根据下面注释中的内容可以知道,@Import允许导入ImportSelector,ImportBeanDefinitionRegistrar的实现类,还有普通的类(在版本4.2后)

    Allows for importing {@code @Configuration} classes, {@link ImportSelector} and {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}).
    

    到了这里,说一个与@Import注解相关的东西,Spring框架本身提供了几个以Enable打头的注解,根据名字可知这是开启某个功能,比如@EnableScheduling@EnableCaching@EnableMBeanExport等,@EnableAutoConfiguration的理念和这些注解其实是相同的的。

    @EnableScheduling是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。@EnableMBeanExport是通过@Import将JMX相关的bean定义加载到IoC容器。

    @EnableAutoConfiguration也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。

    接下来关注EnableAutoConfigurationImportSelector 这个作用是什么。主要就是使用Spring 4 提供的的SpringFactoriesLoader工具类。通过SpringFactoriesLoader.loadFactoryNames()读取了ClassPath下面的META-INF/spring.factories文件

    EnableAutoConfigurationImportSelector通过读取spring.factories中的key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的值。如spring-boot-autoconfigure-1.5.1.RELEASE.jar中的spring.factories文件包含以下内容:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
    org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,
    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,
    org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,
    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,
    org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,
    org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,
    org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,
    

    如果我们新定义了一个starter的话,也要在该starterjar包中提供 META-INFO/spring.factories文件,并且为其配置org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置类

    EnableAutoConfiguration寻找一个配置类CacheAutoConfiguration

    @Configuration
    @ConditionalOnClass(CacheManager.class)
    @ConditionalOnBean(CacheAspectSupport.class)
    @ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
    @EnableConfigurationProperties(CacheProperties.class)
    @AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
    		HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
    @Import(CacheConfigurationImportSelector.class)
    public class CacheAutoConfiguration {
    
    	@Bean
    	@ConditionalOnMissingBean
    	public CacheManagerCustomizers cacheManagerCustomizers(
    			ObjectProvider<List<CacheManagerCustomizer<?>>> customizers) {
    		return new CacheManagerCustomizers(customizers.getIfAvailable());
    	}
        .......
    }
    

    这是一个@Configuration配置类,包含@Bean的方法的返回值会注册为一个bean

    在这个类和方法上我们看到很多条件配置注解

    条件配置主要的注解是@Conditional,这个注解指定一个实现了Condition的类,类中实现了matchs方法,如果方法返回true,被@Conditional修饰的类或者方法才会创建bean。为了方便Spring4中已经帮我们实现了一些常用的条件配置注解

    @ConditionalOnBean
    @ConditionalOnClass
    @ConditionalOnExpression
    @ConditionalOnMissingBean
    @ConditionalOnMissingClass
    @ConditionalOnNotWebApplication
    

    至此,我们已经分析了SpringBoot中自动化配置的基本原理,接下来我们会编写一个spring-boot-starter

  • 相关阅读:
    Django信号机制相关解释与示例
    花了三个月终于把所有的 Python 库全部整理了!可以说很全面了
    Django3.0 异步通信初体验(小结)
    基于docker-compose搭建本地sentry服务
    权限控制终于来了!Redis 6.0新特性——ACLs
    redis为什么是单线程而且速度快?
    Notepad++ 异常崩溃 未保存的new *文件列表没了怎么办?
    Umi + Dva + Antd的React项目实践
    Windows下同时安装python2和python3如何兼容版本
    consul实现kubernetes-1.15集群master的高可用访问实现
  • 原文地址:https://www.cnblogs.com/watertreestar/p/11780286.html
Copyright © 2020-2023  润新知