相信有一部分人跟我一样,是在使用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、@Conditionalspring 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({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