SpringBoot自动化配置之二:自动配置(AutoConfigure)原理

相信有一部分人跟我一样,是在使用spring boot的时候接触到autoconfigure这种风格的配置的,但其实这并不是spring boot才有的,从spring framework3.1开始,这个特性就有了,像@EnableAspectJAutoProxy、@EnableAsync都是从spring 3.1开始就有了。org.springframework.context.annotation包下面拥有自动配置的所有的相关的基础设施。

基础设施
org.springframework.context.annotation包下面提供了各种基于注解配置的基础设施:
1. @Profile:可跟@Bean配合、
2. @Bean、@Scope、@DependsOn、@Primary、@Lazy、@Role、@Description:
3. @Conditional、Condition:@Conditional注解标识在类或者方法上,标识在方法上,符合条件,创建该方法的返回值类型的Bean;标识在类上,符合条件全部创建。
4. @Import(@ImportResource):
5. @Configuration表示的Class(@EnableLoadTimeWeaving)、ImportSelector接口实现(@EnableAsync)或者ImportBeanDefinitionRegistrar接口实现(@EnableAspectJAutoProxy)
6. ImportSelector、DeferredImportSelector:
7. ImportRegistry
8. ImportBeanDefinitionRegistrar:用来手动注册bean定义的, 可以实现类似于Mybatis-Spring提供的扫描Mapper接口并注册其bean定义, 事实上@MapperScan注解就@Import了MapperScannerRegistrar这个类, 而这个类实现了上面的接口, 来扫描Mapper并注册bean定义.再多说点吧, Spring解析Java配置类的时候, 会判断类是不是标注了@Import注解, 然后会判断, 如果Import注解的value是ImportBeanDefinitionRegistrar类型, 会存到一个变量, 后面初始化bean工程完成后, 会回调ImportBeanDefinitionRegistrar.
9. @Configuration:跟@Controller、@Servcice和@Repository是一样的套路,都用@Component注解了,作为特定类型的组件
10. @PropertySource
11. Condition、ConfigurationCondition、@Conditional

spring boot autoconfigure
Spring Boot AutoConfigure替代了XML风格的配置文件,带来了前所未有的体验。Spring Boot AutoConfigure模块基于Spring Framework和Spring Boot提供的基础设施,构建类配置Bean+属性文件配置行为的配置方式,Java类配置Bean为我们提供了更好的编程体验,属性文件配置行为的方式使这种方式拥有跟XML外部配置文件配置方式同样的灵活性。

org.springframework.boot.autoconfigure
首先,Spring Boot AutoConfigure在Spring Framework和Spring Boot提供的基础设施上做了很多的扩展工作:
1. 顺序控制:AutoConfigureOrder、AutoConfigureAfter、AutoConfigureBefore;
2. AutoConfigurationPackage:在spring boot mian class上标识EnableAutoConfiguration之后,所有子包下面的spring 组件都能被扫描到,就是这个注解的能力;
3. EnableAutoConfiguration/ImportAutoConfiguration:EnableAutoConfiguration开启自动配置,自动应用spring.factories中配置的哥哥*AutoConfiguration;ImportAutoConfiguration跟EnableAutoConfiguration相比,只是没有自动配置的功能,给ImportAutoConfiguration传入谁的AutoConfiguration就应用谁的,单元测试等的场景用到的比较多;
4. 其他的一些工具类,过滤器之类的东西大家可以自己去看下

org.springframework.boot.autoconfigure.context.condition
ConditionalOnCloudPlatform:是否在云环境下,spring boot cloud模块提供了两种实现,CLOUD_FOUNDRY和HEROKU,国内应该用不到这个注解了
ConditionalOnJava:指定的Java版本
ConditionalOnWebApplication:是Web环境的时候
ConditionalOnNotWebApplication:不是web环境的时候
ConditionalOnJndi:JNDI环境下使用
ConditionalOnClass:classpath中存在某个类
ConditionalOnMissingClass:classpath中不存在某个类
ConditionalOnBean:BeanFactory中存在某个类的Bean
ConditionalOnMissingBean:BeanFactory中不存在某个类的Bean
ConditionalOnExpression:SpEL的结果
ConditionalOnProperty:Environment中是否有某个属性的配置信息
ConditionalOnResource:classpath中是否存在指定名称的资源
ConditionalOnSingleCandidate:指定的类在BeanFactory中只有一个候选的bean,或者有多个候选的bean,但是其中一个指定了primary时
各种*AutoConfiguration的实现:
所有的*AutoConfiguration的具体实现包括两部分,一个是标识了@Configuration注解的配置类,另一个是Property文件。有些模块比较复杂,像security的oauth2模块,主要文件也是这两类,剩下的是一些工具。

*AutoConfiguration也是Configuration,被@Configuration注解,只不过spring boot autoconfigure模块内置的 *AutoConfiguration被配置到了 spring.factories文件中,启动的时候自动配置。

自动配置是Spring Boot的最大亮点,完美的展示了CoC约定由于配置。Spring Boot能自动配置Spring各种子项目(Spring MVC, Spring Security, Spring Data, Spring Cloud, Spring Integration, Spring Batch等)以及第三方开源框架所需要定义的各种Bean。 
Spring Boot内部定义了各种各样的XxxxAutoConfiguration配置类,预先定义好了各种所需的Bean。只有在特定的情况下这些配置类才会被起效。 
(1)如何导入的自动配置类 
查看源码可以看看自动配置类是如何被引入的。 
a) 应用入口 

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

b) 类注解 @SpringBootApplication = @EnableAutoConfiguration + @ComponentScan + @Configuration 

@SpringBootConfiguration  
@EnableAutoConfiguration  
@ComponentScan(excludeFilters = {  
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),  
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })  
public @interface SpringBootApplication {  
    // ...  
}  
  
@Configuration  
public @interface SpringBootConfiguration {  
    // ...  
}  

c)开启自动配置注解 @EnableAutoConfiguration 

@AutoConfigurationPackage  
@Import(EnableAutoConfigurationImportSelector.class)  
public @interface EnableAutoConfiguration {  
    // ...  
}  

d)导入配置类 EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector
在AutoConfigurationImportSelector类中可以看到通过 SpringFactoriesLoader.loadFactoryNames() 把 spring-boot-autoconfigure-1.5.10.RELEASE.jar/META-INF/spring.factories 下 

应用启动后是如何加载这些类的呢? 
通过执行SpringApplication.run()方法,会把当前的SpringBootDemoApplication作为source传入而在SpringApplication类中还会读取spring.factories中的设置一并构建应用的Context。 
spring-boot-1.5.10.RELEASE.jar/META-INF/spring.factories 

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer

spring-boot-autoconfigure-1.5.10.RELEASE.jar/META-INF/spring.factories 

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

相应在做war时也是把当前的SpringBootDemoApplication作为source传给了ServletInitializer。 

public class ServletInitializer extends SpringBootServletInitializer {  
    @Override  
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {  
        return application.sources(SpringBootDemoApplication.class);  
    }  
}  

配置类也可自行导入 

@Configuration  
@Import({  
        DispatcherServletAutoConfiguration.class,  
        EmbeddedServletContainerAutoConfiguration.class,  
        ErrorMvcAutoConfiguration.class,  
        HttpEncodingAutoConfiguration.class,  
        HttpMessageConvertersAutoConfiguration.class,  
        JacksonAutoConfiguration.class,  
        MultipartAutoConfiguration.class,  
        ServerPropertiesAutoConfiguration.class,  
        WebMvcAutoConfiguration.class  
})  
@ComponentScan  
public class SpringBootDemoApplication {  
    public static void main(String[] args) {  
        SpringApplication.run(SpringBootDemoApplication.class, args);  
    }  
}  

(2)自动配置类内部构成 
举例查看 org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration 

@Configuration  
@ConditionalOnWebApplication(type = Type.SERVLET)  
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class })  
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)  
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)  
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class })  
public class WebMvcAutoConfiguration {
  
    @Bean  
    @ConditionalOnMissingBean(HiddenHttpMethodFilter.class)  
    public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {  
        return new OrderedHiddenHttpMethodFilter();  
    }  
  
    // ...  
  
}  

条件配置 基于Spring的@Conditional,SpringBoot提供了丰富的条件配置: 

@ConditionalOnClass : classpath中存在该类时起效 
@ConditionalOnMissingClass : classpath中不存在该类时起效 
@ConditionalOnBean : DI容器中存在该类型Bean时起效 
@ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效 
@ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效 
@ConditionalOnExpression : SpEL表达式结果为true时 
@ConditionalOnProperty : 参数设置或者值一致时起效 
@ConditionalOnResource : 指定的文件存在时起效 
@ConditionalOnJndi : 指定的JNDI存在时起效 
@ConditionalOnJava : 指定的Java版本存在时起效 
@ConditionalOnWebApplication : Web应用环境下起效 
@ConditionalOnNotWebApplication : 非Web应用环境下起效

 更多关于@Conditional的见《spring4.0之五:@Conditional在满足特定条件下,才会实例化对象

@Conditional({OnClassCondition.class})  
public @interface ConditionalOnClass {  
    // ...  
}  
OnClassCondition.java
public class OnClassCondition extends SpringBootCondition implements ... {  
    // ...  
    // MatchType.PRESENT 判断classpath里是否存在指定类  
}  

SpringBootCondition.java

public abstract class SpringBootCondition implements Condition {  
    // ...  
} 

执行顺序 

引用
@AutoConfigureAfter:在指定的配置类初始化后再加载 
@AutoConfigureBefore:在指定的配置类初始化前加载 
@AutoConfigureOrder:数越小越先初始化
 
(3)查看项目实际配置了什么 

运行时开启DEBUG模式后即可在控制台看到具体的自动配置结果。 
/src/main/resources/application.properties 

debug=true
========================= 
AUTO-CONFIGURATION REPORT 
========================= 

Positive matches: 
----------------- 
   DispatcherServletAutoConfiguration matched: 
      - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class 
(OnClassCondition) 
      - @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition) 
   DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched: 
      - @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class 
(OnClassCondition) 
      - Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition) 
....... 
Negative matches: 
----------------- 
   ActiveMQAutoConfiguration: 
      Did not match: 
         - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' 
(OnClassCondition) 
   AopAutoConfiguration: 
      Did not match: 
         - @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition) 
.......
Exclusions: 
----------- 
    None 
Unconditional classes: 
---------------------- 
    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration 
  org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration 
    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration 
   org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration

比如可以看到SpringBoot默认开启了: 

DispatcherServletAutoConfiguration 注册DispatcherServlet 
EmbeddedServletContainerAutoConfiguration.EmbeddedTomcat 注册Tomcat容器 
ErrorMvcAutoConfiguration 注册异常处理器 
HttpEncodingAutoConfiguration 注册编码过滤器CharacterEncodingFilter 
HttpMessageConvertersAutoConfiguration 注册json或者xml处理器 
JacksonAutoConfiguration 注册json对象解析器 
MultipartAutoConfiguration 注册文件传输处理器 
TransactionAutoConfiguration 注册事物管理处理器 
ValidationAutoConfiguration 注册数据校验处理器 
WebMvcAutoConfiguration 注册SpringMvc相关处理器

(4)关闭自动配置 

全体无效化 

a)使用@Configuration @ComponentScan 代替 @SpringBootApplication。 
b)参数设置 
src/main/resources/application.properties 

spring.boot.enableautoconfiguration=false

c)部分无效化 

@SpringBootApplication(exclude=HibernateJpaAutoConfiguration.class)  

或 
src/main/resources/application.properties 

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})  

或 
src/main/resources/application.properties 

spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
spring.autoconfigure.exclude[1]=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.autoconfigure.exclude[2]=org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
spring.autoconfigure.exclude[3]=org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration

参考: 
http://qiita.com/kazuki43zoo/items/8645d9765edd11c6f1dd 
http://d.hatena.ne.jp/Kazuhira/20170219/1487513127

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值