在日常的开发过程中Spring Boot
自动装配的特性给我们开发减少了很多重复性的工作,具体时如果实现自动装配的呢,我们会在下一篇文章做详细的分析,以及用源码解析跟实战方式带大家了解Spring Boot
“自动化”的原因,我们将透过现象去发现本质。
Spring Boot介绍:
Create stand-alone Spring applications
-- 创建一个独立的Spring应用
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
-- 嵌入式的web服务器Tomcat、Jetty、Undertow(无需部署 war 文件)
Provide opinionated 'starter' dependencies to simplify your build configuration
-- 提供建议的 "启动" 依赖关系, 以简化生成配置
Automatically configure Spring and 3rd party libraries whenever possible
-- 尽可能自动配置 spring 和第三方库
Provide production-ready features such as metrics, health checks and externalized configuration
-- 具备为生产准备的特性,如指标、运行状况检查和外部化配置
Absolutely no code generation and no requirement for XML configuration
-- 尽可能的无需代码生成并且无XML配置
话不多说,开始进入本次分享的主题,在Spring Boot
中@EnableAutoConfiguration
的使用显得十分普遍,使用越多遇到的问题可能也就越多。为什么笔者会这样说呢,因为在程序开发的过程中,引入新技术一般会有两个原因:
第一:更便捷,能明显提高开发效率,否则一般的团队很少会主动尝试新事物。毕竟新的就意味着有风险
第二:对程序有显著地提升(此处是指可以是性能,也可以是健壮性,可用性,并发处理能力等等)
注解名称 | 作用 |
---|---|
@Component | 基础注解(元注解),可被嵌套 |
@Configuration | 声明定义Bean,嵌套了@Component |
@Import | 导入类(如AutoConfigurationImportSelector.class) |
@ImportResource | 导入文件("classpath:/com/acme/database-config.xml") |
@AutoConfigureAfter | 条件注解控制相对顺序(在条件注入之后注入),Order实现绝对顺序控制 |
@ConditionalOnClass | 当类存在时装配 |
@ConditionalOnMissingClass | 当类不存在时装配 |
@EnableAutoConfiguration | 使用该注解实现自动装配 |
@SpringBootConfiguration | 包含@Configuration,启动类的标注 |
@PropertySource | properties文件加载 |
@ConditionalOnSystemProperty | properties文件中存在满足条件的属性时装配 |
@EnableConfigurationProperties | 是带有@ConfigurationProperties注解的类生效 |
在实际的使用中h还会有很多注解的定义与使用,在我们的日常开发中需要根据实际情况去选择使用。
由于Spring Boot
自动装配的特性,所以在jar
引入后,我们会得到Spring
容器为我们量身定做的实例,即我们所谓的Bean
,这个过程中当然不可或缺的有RestTemplate
,使用JDBC
或者MyBatis
等时会有JdbcTemplate
生成。
//在Spring Boot中通过@EnableAutoConfiguration实现自动装配对象的选择
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//具体选择器实现
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
该示例即为RestTemplate
自动注入,包含条件注解:在HttpMessageConvertersAutoConfiguration
自动注入之后;在RestTemplate.class
存在时注入
@Configuration
@AutoConfigureAfter(HttpMessageConvertersAutoConfiguration.class)
@ConditionalOnClass(RestTemplate.class)
public class RestTemplateAutoConfiguration {
...
@Bean
}
该示例即为JdbcTemplate
自动注入,包含条件注解:在DataSourceAutoConfiguration
自动注入之后;在JdbcTemplate.class
和DataSource.class
并且DataSource
为单例时,存在时注入
@Configuration
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcTemplateAutoConfiguration {
@Bean
@Bean
@Primary
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcTemplate jdbcTemplate() {
...
}
}
RestTemplateAutoConfiguration
和JdbcTemplateAutoConfiguration
在spring-boot-autoconfiguration包下的META-INF/spring.factories
中声明
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration
而后被AutoConfigurationImportSelector
选择加载,该类实现了ImportSelector
接口,具体加载的位置在invokeBeanFactoryPostProcessors(beanFactory);
注册的时候,实现Bean
的注册;而在Bean
注册之前会有BeanClass
,Resource
,Environment
等的属性注入;Ordered
接口主要是确定加载的顺序。
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
...
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
如上所述可以实现,RestTemplateAutoConfiguration
和JdbcTemplateAutoConfiguration
的自动注入得以实现。
# 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,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
首先梳理自动装配的流程
定义HelloWorldAutoConfiguration
/**
* @ClassName: HelloWorldAutoConfiguration
* @Description: HelloWorld 自动装配
* @Author: 尚先生
* @CreateDate: 2019/1/28
* @Version: 1.0
*/
@Configuration // Spring 模式注解装配
@EnableHelloWorld // Spring @Enable 模块装配
public class HelloWorldAutoConfiguration {
@Bean
public String helloWorld() { // 方法名即 Bean 名称
return "Hello,World sxs";
}
}
配置注解标记类
/**
* @ClassName: EnableHelloWorld
* @Description: HelloWorld 自动装配注解
* @Author: 尚先生
* @CreateDate: 2019/1/28
* @Version: 1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}
配置META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sxs.springboot.configuration.HelloWorldAutoConfiguration
/**
* @ClassName: EnableHelloWorldBootstrap
* @Description: HelloWorld 自动装配引导类(测试类)
* @Author: 尚先生
* @CreateDate: 2019/1/28
* @Version: 1.0
*/
@EnableHelloWorld
public class EnableHelloWorldBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableHelloWorldBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
// helloWorld Bean 是否存在
String helloWorld = context.getBean("helloWorld", String.class);
System.out.println("helloWorld Bean : " + helloWorld);
// 关闭上下文
context.close();
}
}
helloWorld Bean : Hello,World sxs
1. 通过各种注解实现了类与类之间的依赖关系,容器在启动的时候Application.run,会调用EnableAutoConfigurationImportSelector.class的selectImports方法(其实是其父类的方法)
2. selectImports方法最终会调用SpringFactoriesLoader.loadFactoryNames方法来获取一个全面的常用BeanConfiguration列表
3. loadFactoryNames方法会读取FACTORIES_RESOURCE_LOCATION(也就是spring-boot-autoconfigure.jar 下面的spring.factories),获取到所有的Spring相关的Bean的全限定名ClassName,大概120多个
4. selectImports方法继续调用filter(configurations, autoConfigurationMetadata);这个时候会根据这些BeanConfiguration里面的条件,来一一筛选,最关键的是
@ConditionalOnClass,这个条件注解会去classpath下查找,jar包里面是否有这个条件依赖类,所以必须有了相应的jar包,才有这些依赖类,才会生成IOC环境需要的一些默认配置Bean
5. 最后把符合条件的BeanConfiguration注入默认的EnableConfigurationPropertie类里面的属性值,并且注入到IOC环境当中
博客地址:https://blog.csdn.net/shang_xs
微信公众号地址:http://mp.weixin.qq.com/mp/homepage?__biz=MzUxMzk4MDc1OQ==&hid=2&sn=c6c58c06f6f8403af27b6743648b3055&scene=18#wechat_redirect