文章已经收录在 Github.com/niumoo/JavaNotes ,更有 Java 程序员所须要掌握的核心知识,欢迎Star和指教。
欢迎关注个人 公众号,文章每周更新。注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不一样可能会有细微差异。html
关于配置文件能够配置的内容,在 Spring Boot 官方网站已经提供了完整了配置示例和解释。java
能够这么说,Spring Boot 的一大精髓就是自动配置,为开发省去了大量的配置时间,能够更快的融入业务逻辑的开发,那么自动配置是怎么实现的呢?
<!-- more -->git
@SpringBootApplication
跟着 Spring Boot 的启动类的注解 @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} )} ) public @interface SpringBootApplication {
@EnableAutoConfiguration
开启自动配置。github
@ComponentScan
开启注解扫描web
从 SpringBootApplication
咱们能够发现,这是一个简便的注解配置,它包含了自动配置,配置类,包扫描等一系列功能。面试
@EnableAutoConfiguration
继续跟踪,查看@EnableAutoConfiguration
源码,里面比较重要的是 @Import
,导入了一个翻译名为自动配置的选择器的类。这个类其实就是自动配置的加载选择器。spring
@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 {}; }
继续跟踪 AutoConfigurationImportSelector.class
.在这个类有一个重要的方法 getCandidateConfigurations
.用于加载 Spring Boot 配置的自动配置类。json
getAutoConfigurationEntry
会筛选出有效的自动配置类。springboot
protected AutoConfigurationEntry getAutoConfigurationEntry( AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
下图是 DEBUG 模式下筛选以后的结果,由于我只添加了 web 模块,因此只有 web 相关的自动配置。
在上面的 debug 里,咱们看到了成功加载的自动配置,目前只看到了配置类,却尚未发现自动配置值,随便选择一个 AutoConfiguration
查看源码。
这里选择了 ServletWebServerFactoryAutoConfiguration
.
@Configuration @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) //判断当前项目有没有这个类 //CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器; @ConditionalOnClass(ServletRequest.class) //Spring底层@Conditional注解(Spring注解版),根据不一样的条件,若是 //知足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是不是web应用,若是是,当前配置类生效 @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration {
须要注意的是 @EnableConfigurationProperties(ServerProperties.class)
.他的意思是启动指定类的ConfigurationProperties
功能;将配置文件中对应的值和 ServerProperties
绑定起来;并把ServerProperties
加入到 IOC 容器中。
再来看一下 ServerProperties
.
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { /** * Server HTTP port. */ private Integer port;
显而易见了,这里使用 ConfigurationProperties 绑定属性映射文件中的 server 开头的属性。结合默认配置
# 路径spring-boot-autoconfigure-2.1.1.RELEASE.jar # /META-INF/spring-configuration-metadata.json { "name": "server.port", "type": "java.lang.Integer", "description": "Server HTTP port.", "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties", "defaultValue": 8080 }
达到了自动配置的目的。
经过自动配置,咱们发现已经帮咱们省去了大量的配置文件的编写,那么在自定义配置的时候,咱们是否是须要编写XML呢?Spring boot 尽管可使用 SpringApplication
XML 文件进行配置,可是咱们一般会使用 @Configuration
类进行代替,这也是官方推荐的方式。
定义 helloService Bean.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloService" class="net.codingme.boot.service.HelloService"></bean> </beans>
引入配置。
@ImportResource(value = "classpath:spring-service.xml") @SpringBootApplication public class BootApplication { public static void main(String[] args) { SpringApplication.run(BootApplication.class, args); } }
此种方式和上面的XML配置是等效的,也是官方推荐的方式。@Configuration
注解的类(要在扫描的包路径中)会被扫描到。
/** * <p> * 配置类,至关于传统Spring 开发中的 xml-> bean的配置 * * @Author niujinpeng * @Date 2018/12/7 0:04 */ @Configuration public class ServiceConfig { /** * 默认添加到容器中的 ID 为方法名(helloService) * * @return */ @Bean public HelloService helloService() { return new HelloService(); } }
@Conditional扩展注解 | 做用(判断是否知足当前指定条件) |
---|---|
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean; |
@ConditionalOnMissingBean | 容器中不存在指定Bean; |
@ConditionalOnExpression | 知足SpEL表达式指定 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
文章代码已经上传到 GitHub Spring Boot 自动配置。
最后的话
文章已经收录在 Github.com/niumoo/JavaNotes ,欢迎Star和指教。更有一线大厂面试点,Java程序员须要掌握的核心知识等文章,也整理了不少个人文字,欢迎 Star 和完善,但愿咱们一块儿变得优秀。
文章有帮助能够点个「赞」或「分享」,都是支持,我都喜欢!
文章每周持续更新,要实时关注我更新的文章以及分享的干货,能够关注「 未读代码 」公众号或者个人博客。