Spring Boot 自动配置
Spring Boot Auto-configuration
spring boot相比spring之所以简化很多就是因为spring boot搭建一个项目的时候可以引入多个starter,这样就可以直接使用不需要过多的各种配置。spring官方提供了不少starter,而我们自己也可以自定义starter,为了能够区分,从命名上进行了规范。官方的starter名称为:spring-boot-starter-xxx,而自定义的为xxx-spring-boot-starter。
什么是 Spring Boot 自动装配
提到自动装配的时候,一般会和 Spring Boot 联系在一起。但是,实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进一步优化。
SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的
META-INF/spring.factories
文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。
没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。
|
|
引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。
在我看来,自动装配可以简单理解为:通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。
SpringBoot 是如何实现自动装配
@SpringBootApplication
等同于下面三个注解:
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilter
和AutoConfigurationExcludeFilter
。
其中@EnableAutoConfiguration
是关键(启用自动配置),内部实际上就去加载META-INF/spring.factories
文件的信息,然后筛选出以EnableAutoConfiguration
为key的数据,加载到IOC容器中,实现自动配置功能!
@EnableAutoConfiguration注释,此注释自动载入应用程序所需的所有Bean,这依赖于Spring Boot在类路径中的查找。
Test Auto-configuration Annotations
@EnableAutoConfiguration
|
|
显然通过@Import 注解导入 spring-boot-autoconfigure-*.jar
中的 AutoConfigurationImportSelector
类。
|
|
使用了Spring Core包的 SpringFactoriesLoader
类的 loadFactoryNames()
方法。 查询spring-boot-autoconfigure-*.jar
META-INF/spring.factories文件中 spring.factories
文件
# Auto Configure
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,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
以上为Spring Boot中所有的自动配置相关类;在启动过程中会解析对应类配置信息
解析 MongoAutoConfiguration
以Mongo为例,则会去解析MongoAutoConfiguration
|
|
@ConditionOnClass激活一个配置,在类路径中只能存在一到几个这样的类。 2)@EnableConfigurationProperties自动映射一个POJO到Spring Boot配置文件(默认是application.properties文件)的属性集。 3)@ConditionalOnMissingBean启用一个Bean定义,但必须是这个Bean之前未定义过才有效。 还可以使用@ AutoConfigureBefore注释、@AutoConfigureAfter注释来定义这些配置类的载入顺序。
属性映射
下面看MongoProperties类,它是一个Spring Boot属性映射的例子:
|
|
@ConfigurationProperties注释将POJO关联到指定前缀的每一个属性。例如,spring.data.mongodb.port属性将映射到这个类的端口属性。
@Conditional 注释
Spring Boot的强大之处在于使用了Spring 4框架的新特性:@Conditional注释,此注释使得只有在特定条件满足时才启用一些配置。 在Spring Boot的org.springframework.boot.autoconfigure.condition包中说明了使用@Conditional注释能给我们带来什么,下面对这些注释做一个概述:
Spring Boot 提供的条件注解
@ConditionalOnBean
:当容器里有指定 Bean 的条件下@ConditionalOnMissingBean
:当容器里没有指定 Bean 的情况下@ConditionalOnSingleCandidate
:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean@ConditionalOnClass
:当类路径下有指定类的条件下@ConditionalOnMissingClass
:当类路径下没有指定类的条件下@ConditionalOnProperty
:指定的属性是否有指定的值@ConditionalOnResource
:类路径是否有指定的值@ConditionalOnExpression
:基于 SpEL 表达式作为判断条件@ConditionalOnJava
:基于 Java 版本作为判断条件@ConditionalOnJndi
:在 JNDI 存在的条件下差在指定的位置@ConditionalOnNotWebApplication
:当前项目不是 Web 项目的条件下@ConditionalOnWebApplication
:当前项目是 Web 项 目的条件下
以@ConditionalOnExpression注释为例,它允许在Spring的EL表达式中写一个条件。
|
|
在这个类中,我们想利用@Conditional注释,条件在OnExpressionCondition类中定义:
|
|
在最后,@Conditional通过简单的布尔表达式(即ConditionOutcome方法)来决定。
应用程序上下文初始化器
spring.factories 还提供了第二种可能性,即定义应用程序的初始化。这使得我们可以在应用程序载入前操纵Spring的应用程序上下文ApplicationContext。 特别是,可以在上下文创建监听器,使用ConfigurableApplicationContext类的addApplicationListener()方法。 AutoConfigurationReportLoggingInitializer监听到系统事件时,比如上下文刷新或应用程序启动故障之类的事件,Spring Boot可以执行一些工作。这有助于我们以调试模式启动应用程序时创建自动配置的报告。 要以调试模式启动应用程序,可以使用-Ddebug标识,或者在application.properties文件这添加属性debug= true。
调试Spring Boot自动配置
Spring Boot的 官方文档 有助于理解自动配置期间发生了什么。当以调试模式运行时,Spring Boot会产生一个报告,如下:
Positive matches:
-----------------
MessageSourceAutoConfiguration
- @ConditionalOnMissingBean (types: org.springframework.context.MessageSource; SearchStrategy: all) found no beans (OnBeanCondition)
JmxAutoConfiguration
- @ConditionalOnClass classes found: org.springframework.jmx.export.MBeanExporter (OnClassCondition)
- SpEL expression on org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration: ${spring.jmx.enabled:true} (OnExpressionCondition)
- @ConditionalOnMissingBean (types: org.springframework.jmx.export.MBeanExporter; SearchStrategy: all) found no beans (OnBeanCondition)
DispatcherServletAutoConfiguration
- found web application StandardServletEnvironment (OnWebApplicationCondition)
- @ConditionalOnClass classes found: org.springframework.web.servlet.DispatcherServlet (OnClassCondition)
Negative matches:
-----------------
DataSourceAutoConfiguration
- required @ConditionalOnClass classes not found: org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType (OnClassCondition)
DataSourceTransactionManagerAutoConfiguration
- required @ConditionalOnClass classes not found: org.springframework.jdbc.core.JdbcTemplate,org.springframework.transaction.PlatformTransactionManager (OnClassCondition)
MongoAutoConfiguration
- required @ConditionalOnClass classes not found: com.mongodb.Mongo (OnClassCondition)
FallbackWebSecurityAutoConfiguration
- SpEL expression on org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration: !${security.basic.enabled:true} (OnExpressionCondition)
SecurityAutoConfiguration
- required @ConditionalOnClass classes not found: org.springframework.security.authentication.AuthenticationManager (OnClassCondition)
EmbeddedServletContainerAutoConfiguration.EmbeddedJetty
- required @ConditionalOnClass classes not found: org.eclipse.jetty.server.Server,org.eclipse.jetty.util.Loader (OnClassCondition)
WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#localeResolver
- @ConditionalOnMissingBean (types: org.springframework.web.servlet.LocaleResolver; SearchStrategy: all) found no beans (OnBeanCondition)
- SpEL expression: '${spring.mvc.locale:}' != '' (OnExpressionCondition)
WebSocketAutoConfiguration
- required @ConditionalOnClass classes not found: org.springframework.web.socket.WebSocketHandler,org.apache.tomcat.websocket.server.WsSci (OnClassCondition)
对于每个自动配置,可以看到它启动或失败的原因。
自定义 EnableAutoConfiguration
|
|
- 自定义EnableAutoConfigurationImport,注入了ClassLoader,并调用SpringFactoriesLoader.loadFactoryNames()方法,导出Configuration的类。
|
|
入口类,这里使用了MyEnableAutoConfiguration注解。
|
|
如何实现一个 Starter
总结
@EnableAutoConfiguration 作用 从classpath中搜索所有META-INF/spring.factories配置文件然后,将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration key对应的配置项加载到spring容器 只有spring.boot.enableautoconfiguration为true(默认为true)的时候,才启用自动配置
@EnableAutoConfiguration还可以进行排除,排除方式有2中,一是根据class来排除(exclude),二是根据class name(excludeName)来排除 其内部实现的关键点有 1)ImportSelector 该接口的方法的返回值都会被纳入到spring容器管理中
|
|
2)SpringFactoriesLoader 该类可以从classpath中搜索所有META-INF/spring.factories配置文件,并读取配置