Spring Boot众所周知是为了简化Spring的配置,省去XML的复杂化配置(虽然Spring官方推荐也使用Java配置)采用Java+Annotation方式配置。以下几个问题是我刚开始接触Spring Boot的时候常常遇到的一些疑问,如今总结出来但愿能帮助到更多的人理解Spring Boot,固然这只是我的的理解,稍微显得肤浅但易懂!当时我明白了如下几个问题后,以为Spring Boot也不过如此,没有啥花里胡哨的,但愿能帮到你们!java
本博文主要由两个部分组成:第一篇经过源码等形式介绍自动配置的原理与组成部分,第二篇经过实现自定义的starter实现自动配置加深对自动配置的理解。mysql
注:创做不易啊,虽然写只写了5个小时左右,可是整个准备过程很早就开始了,固然这样的记录方式主要是督促本身对Spring Boot要深刻理解,顺带但愿能帮到更多人redis
问题一:那么Spring Boot是靠什么样的手段简化配置呢?spring
从广义上讲,从软件设计范式来讲。Spring Boot提供一种“约定优于配置”来简化配置;减小开发人员去开发不必的配置模块时间,采用约定,而且对不符合约定的部分采用灵活配置知足便可!sql
问题二:那么什么叫约定优于配置呢?服务器
好比:咱们知道Spring Boot都是内嵌Tomcat、Jetty等服务器的,其中默认的Tomcat服务器,相应的监听端口也默认绑定,这些默认即为约定。大部分状况下咱们都会使用默认默认的Spring Boot自带的内嵌的默认自动配置约定,不会大量去自定义配置,即这就是我理解的约定优于配置。那么问题三来了。当咱们以为不符合咱们实际生产环境的时候才会去改变默认配置,那么须要很麻烦的手段吗?app
问题三:更改默认的端口或者服务器(即上述提到的约定)须要很麻烦的代码编写吗?甚至须要更改源码吗?spring-boot
答案确定是否认的,只须要更改application.yml/properties(application-*.yml/properties)配置文件便可。固然也能够从源头上开始从新建立本身须要的模块(准确来讲能够是starter),须要的注册的配置类Bean。从而达到灵活的自动配置目的,这就是本篇要介绍的Spring Boot的自动配置。spa
明白以上三个问题后,其实就能理解为何Spring Boot相对于Spring更加灵活,方便,简单的缘由了========>无非就是大量使用默认自动配置+灵活的自动配置设计
主要从spring boot是如何启动后自动检测自动配置与spring boot如何灵活处理自动配置两个方面讲解,前者主要分析源码,从简单的注解入手到最后的读取spring.facoties文件。后者主要举例RedisAutoConfiguration自动配置来讲明spring boot对于相关的配置类bean的经过注解的灵活处理。
都知道Spring Boot程序入口处(xxxApplication.java)都会有 @SpringBootApplication 的注解。这个注解代表该程序是主程序入口,也是SpringBoot应用
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
查看 @SpringBootApplication 注解,不难发现是一个组合注解,包括了 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan 。换句话说这三个注解能够替代 @SpringBootApplication
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} )
其中注解 @EnableAutoConfiguration 就是实现SpringBoot自动配置的关键所在,值得注意的是@EnableXXXX注解并非SpringBoot特有,在Spring 3.x中就已经引出,好比:@EnableWebMvc用来启用Spring MVC而不须要XML配置,@EnableTransactionManagement注释用来声明事务管理而不须要XML配置。如此可见,@EnableXXXX是用来开启某一个特定的功能,从而使用Java来配置,省去XML配置。在SpringBoot中自动配置的开启就是依靠注解 @EnableAutoConfiguration ,继续查看注解接口 @EnableAutoConfiguration
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
其中关键是 @Import({AutoConfigurationImportSelector.class}) ,表示选择全部SpringBoot的自动配置。废话很少说,还得继续看该选择器源码,其中最主要的方法是 getAutoConfiguationEntry 方法,该方法的主要功能是:
得到自动配置---->删除重复自动配置----->删除排除掉的自动配置---->删除过滤掉的自动配置------>最终的自动配置
这里咱们主要关注如何获取自动配置,即图中红圈部分,即 getCandidateConfigurations 方法,该方法经过SpringFactoresLoader.loadFactoryNames方法读取某个classpath下的文件获取全部的configurations
注意到: No auto configuration classes found in META-INF/spring.factories..... ,它应该是从META-INF/spring.factories文件中下读取configurations,咱们再往下查看方法 SpringFactoresLoader.loadFactoryNames ,该方法果真是读取META-INF/spring.factories文件的,从中获取自动配置键值对。
最后,咱们找到META-INF/spring.factories文件(位于spring-boot-autoconfigure下)
查看其内容:
... # 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.CloudServiceConnectorsAutoConfiguration,\ 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,\ ...
这时候才恍然大悟,原来如此。简单总结起来就是,当SpringBoot应用启动读取自动配置以后,从上到下的相关调用栈(文字简单描述)
从spring.factories文件中咱们选取RedisAutoConfiguration举例说明,至于为何选这个呢?这是由于以前我有写过关于Spring Boot整合Redis的相关博文。因此好入手!
首先,仍是同样进入RedisAutoConfiguration(Idea大法好,点击进入便可查看代码)
源码以下,主要关注如下几个注解:
1)@ConditionalOnClass:在当前classpath下是否存在指定类,如果则将当前的配置注册到spring容器。可见其灵活性。相关的@ConditionalXXX注解是spring 4.x推出的灵活注册bean的注解,称之为“条件注解”。有以下一系列条件注解:
一种是@ConditionalOnProperty(prefix = “mysql”, name = “enable”, havingValue = “true”)表示觉得mysql为前缀的mysql.enable属性若是为空或者不是true时不会注册指定Bean,只有mysql.enable属性为true时候才会注册该指定Bean
一种是@ConditionalOnProperty(prefix = “mysql”, name = “enable”, havingValue = “true”, matchIfMissing = true)matchIfMissing表示若是没有以mysql为前缀的enable属性,则为true表示符合条件,能够注册该指定Bean,默认为false。
...........剩下的还有不少,在autoconfigure.condition包下...........
2)@EnableConfigurationProperties:让 @ConfigurationProperties 注解的properties类生效并使用。如让RedisProperties生效并注册到Spring容器中,而且使用!
3)@ConditionalOnMissingBean:当前Spring容器中没有该bean(name或者class指定),则注册该bean到spring容器。
@Configuration @ConditionalOnClass({RedisOperations.class}) @EnableConfigurationProperties({RedisProperties.class}) @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) public class RedisAutoConfiguration { public RedisAutoConfiguration() { } @Bean @ConditionalOnMissingBean( name = {"redisTemplate"} ) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
因而可知Spring Boot对于自动配置的灵活性,能够传递给咱们一种信息,Spring Boot是如何灵活处理自动配置的?
往大了说,就是你能够选择约定使用大量默认配置简化开发过程,你也能够自定义开发过程当中须要的自动配置。往细了说,就是经过各式各样的条件注解注册须要的Bean来实现灵活配置。
那么实现一个自动配置有哪些重要的环节呢?
继续往下看第二部分!
上面只是对自动配置中几个重要的注解作了简单介绍,可是并无介绍要开发一个简单的自动配置须要哪些环节(部分),一样地咱们仍是以RedisAutoConfiguration与RabbitAutoConfiguration为例,主要查看注解头:
RedisAutoConfiguration:
@Configuration @ConditionalOnClass({RedisOperations.class}) @EnableConfigurationProperties({RedisProperties.class}) @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
RabbitAutoConfiguration:
@Configuration @ConditionalOnClass({RabbitTemplate.class, Channel.class}) @EnableConfigurationProperties({RabbitProperties.class}) @Import({RabbitAnnotationDrivenConfiguration.class})
你会发现一般的通常的AutoConfiguration都有@Configuration,@ConditionalOnClass,@EnableConfigurationProperties,@Import 注解:
那么,能够简单总结获得一个自动配置类主要有如下几部分组成(单纯是根据我的理解总结出来的,没有官方说明)
========================================未完待续(下一篇补充自定义starter会涉及自动配置组成部分)==========================================