SpringBoot的核心就是自动配置,自动配置又是基于条件判断来配置Bean。关于自动配置的源码在spring-boot-autoconfigure-2.0.3.RELEASE.jar,在这里看:
查看配置报告
在配置文件中加入如下配置,查看当前已开启和未开启的自动配置报告:
#查看当前项目中已启用和未启用的自动配置的报告
debug: true
启动项目
已开启的配置:
未开启的配置:
SpringBoot运行原理
先看@SpringBootApplication
- @SpringBootConfiguration:标记当前类为配置类
- @EnableAutoConfiguration:开启自动配置
- @ComponentScan:扫描主类所在的同级包以及下级包里的Bean
关键是**@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)导入的配置功能,
AutoConfigurationImportSelector中的方法getCandidateConfigurations,得到待配置的class的类名集合
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
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;
}
通过SpringFactoriesLoader.loadFactoryNames()方法扫描META-INF/spring.factories文件
这文件列出了哪些需要自动配置。
随便打开一个配置类,例如:
都能看到各种各样的条件判断注解,满足条件时就加载这个Bean。
此类的条件注解是:@ConditionalOnProperty
- @ConditionalOnBean:当容器里有指定Bean的条件下
- @ConditionalOnClass:当类路径下有指定的类的条件下
- @ConditionalOnExpression:基于SpEL表达式作为判断条件
- @ConditionalOnJava:基于JVM版本作为判断条件
- @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
- @ConditionalOnMissingBean:当容器里没有指定Bean的情况下
- @ConditionalOnMissingClass:当容器里没有指定类的情况下
- @ConditionalOnWebApplication:当前项目时Web项目的条件下
- @ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
- @ConditionalOnProperty:指定的属性是否有指定的值
- @ConditionalOnResource:类路径是否有指定的值
- @ConditionalOnOnSingleCandidate:当指定Bean在容器中只有一个,或者有多个但是指定首选的Bean
这些注解都组合了@Conditional注解,只是使用了不同的条件。
通过实例,http编码的默认配置来讲解配置流程
双击shift搜索HttpEncodingProperties,这个类型安全的参数绑定的类就为自动配置http默认编码时提供配置参数。
@ConfigurationProperties(prefix = "spring.http.encoding")
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
/**
* Charset of HTTP requests and responses. Added to the "Content-Type" header if not
* set explicitly.
*/
private Charset charset = DEFAULT_CHARSET;//默认编码方式UTF-8
/**
* Whether to force the encoding to the configured charset on HTTP requests and
* responses.
*/
private Boolean force;
/**
* Whether to force the encoding to the configured charset on HTTP requests. Defaults
* to true when "force" has not been specified.
*/
private Boolean forceRequest;
/**
* Whether to force the encoding to the configured charset on HTTP responses.
*/
private Boolean forceResponse;
/**
* Locale in which to encode mapping.
*/
private Map<Locale, Charset> mapping;
省略set/get
}
- @ConfigurationProperties(prefix = “spring.http.encoding”):application配置文件配置时前缀是"spring.http.encoding"
双击shift搜索HttpEncodingAutoConfiguration http编码自动配置类,只截取部分代码
package org.springframework.boot.autoconfigure.web.servlet;
@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final HttpEncodingProperties properties;
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean//设置Bean CharacterEncodingFilter
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
}
- @Configuration:标明为配置类
- @EnableConfigurationProperties(HttpEncodingProperties.class)声明开启属性注入
- @ConditionalOnClass(CharacterEncodingFilter.class)当CharacterEncodingFilter在类路径的条件下
- @ConditionalOnProperty(prefix = “spring.http.encoding”, value = “enabled”, matchIfMissing = true)当spring.http.encoding=enabled的情况下,如果没有设置则默认为true,即条件符合
- @ConditionalOnMissingBean当容器中没有这个Bean时新建Bean
SpringBoot的核心,自动配置的流程大概就是这个样子,下一篇演示创建自己的starter pom。
SpringBoot核心自动配置之创建自己的starter pom maven依赖包