自动配置原理
我们用@SpringBootApplication来告诉系统这个是一个SpringBoot的应用,点进去会发现是有三个注解复合的
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
点击去发现@SpringBootConfiguration上面是一个@Configuration,说明这个是一个配置文件,意思就是说我们的启动类是一个配置文件。可以参考:https://blog.csdn.net/qq_27062249/article/details/118058784
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration
包含了@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage中有一个@Import(AutoConfigurationPackages.Registrar.class)的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage
那么接下来我们就只要分析AutoConfigurationPackages.Registrar.class和AutoConfigurationImportSelector.class里面分别作了啥,我们就大概能请求SpringBoot的自动配置的原理了
- AutoConfigurationPackages.Registrar.class
AutoConfigurationPackages.Registrar实现了ImportBeanDefinitionRegistrar接口(可以参考:https://blog.csdn.net/qq_27062249/article/details/118067295),在Spring的IOC容器初始化的时候回调用ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法,这中间就是把SpringBoot的启动类的包名获取到,让注册到Spring的IOC容器中,用于后面的组件扫描,所有我们只要在主启动类中用注解声明的组件都能被实例化到Spring的IOC容器中,而在主启动类所在包的其他包的组件就不能被扫描到的原因
- AutoConfigurationImportSelector.class
AutoConfigurationImportSelector实现了DeferredImportSelector接口DeferredImportSelector又实现了ImportSelector接口(可以参考:https://blog.csdn.net/qq_27062249/article/details/118067295),ImportSelector在Spring初始化IOC容器的时候会调用ImportSelector的selectImports方法,该方法返回的String类型的数组,其中的值为类的类全名(包名+类名)。其实这里就是加载工程中的META-INF文件夹下的spring.factories文件中的类全名。下面是AutoConfigurationImportSelector类中的getCandidateConfigurations方法,中间就有提到META-INF/spring.factories文件
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
我们在打开spring-boot-autoconfigure的jar包中的META-INF/spring.factories文件,我们就会发现这里有非常多的xxxAutoConfiguration。这些自动配置类就是通过ImportSelector的selectImports方法返回给Spring的IOC容器,然后将这些xxxAutoConfiguration实例化成对应的实例(这里实例化的的时候是条件选择性的实例化的,用到@Conditional的扩展注解实现的,可以参考:https://blog.csdn.net/qq_27062249/article/details/118225625),然后在添加到IOC容器中的。(如果自定义启动器的流程也是这样)
@ComponentScan
包扫描器,排除了TypeExcludeFilter.class和AutoConfigurationExcludeFilter.class。可以参考:https://blog.csdn.net/qq_27062249/article/details/118059454
最佳实践步骤
- 引入场景依赖spring-boot-starter-xxx,具体有哪些可以参考:https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
- 查看哪些配置生效了,哪些配置没有生效以及原因(在配置文件:application.properties中设置debug=true,然后启动工程,看log输出【Positive matches、Negative matches、Unconditional classes】)
Positive matches: //生效的配置 ----------------- AopAutoConfiguration matched: - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition) AopAutoConfiguration.ClassProxyingConfiguration matched: - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition) - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition) DispatcherServletAutoConfiguration matched: - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition) - found 'session' scope (OnWebApplicationCondition) .....省略很多.... Negative matches: //没有启用的配置 ----------------- ActiveMQAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition) AopAutoConfiguration.AspectJAutoProxyingConfiguration: Did not match: - @ConditionalOnClass did not find required class 'org.aspectj.weaver.Advice' (OnClassCondition) ArtemisAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition) .....省略很多.... Exclusions: ----------- None Unconditional classes: //没有启用的配置 ---------------------- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
-
是否需要修改
-
自己分析。根据对应的xxxAutoConfiguration中的xxxProperties类中有哪些属性,然后修改对应的值
-
自定义组件
-
自定义器(xxxCustomizer)
总结
- SpringBoot会加载所有的自动配置类(xxxAutoConfiguration),配置类按照条件进行条件注入,同时为每个自动配置类都有一个对应的xxxProperties的类,用来做配置类
- 生效的配置类就会给容器中装配很多个组件
- 只要容器中有这些组件,就相当于有这些功能了
- SpringBoot优先使用用户自己配置的组件,如果用户没有配置就使用系统自己注入的
- 定制化配置方式
- 用户直接自己注入对应的组件来替换SpringBoot底层组件
- 用户去修改SpringBoot底层组件的属性