一.前言
我在这系列的第一篇文章中已经说过,SpringBoot通过@Import({AutoConfigurationImportSelector.class})使得其在启动的时候,就自动注入了很多的配置类。那么这些配置类是如何被加载到我们的容器中的呢?下面我们来举个例子HttpEncodingAutoConfiguration这个自动配置类。
二.具体的介绍
1.首先我们看看这个类的源码:
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({HttpProperties.class})
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
2.我们对于代码进行逐个解析
2.1.1.@EnableConfigurationProperties({HttpProperties.class}):启动指定类的ConfigurationProperties功能。将配置文件中对应的值和HttpProperties绑定起来;并把HttpProperties加入到ioc容器中,我们看一下HttpProPerties
@ConfigurationProperties(
prefix = "spring.http"
)
public class HttpProperties {
private boolean logRequestDetails;
private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();
public HttpProperties() {
}
这里我们可以看到,该类通过@ConfigurationProperties 注解,表明了该类的成员变量是通过配置文件注入。(具体可以看看@ConfigurationProperties作用)——所以修改了时候,直接在配置文件修改。
继续看回HttpEncodingAutoConfiguration 类
private final Encoding properties;
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
我们可以看到构造方法的入参实际是来着我们上面讲的绑定参数,接着将值传递给HttpEncodingAutoConfiguration 类的Encoding properties
2.2.条件过滤,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)
2.3.条件过滤:判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass({CharacterEncodingFilter.class})
2.4.判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
matchIfMissing :即使我们配置文件中不配置spring.http.encoding.enabled=true,也是默认生效的
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
2.5.这里还要讲解点代码:
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
@Bean 表示将返回的类注入到容器中,然后我们可以发现,该方法中的属性都是来自我们的 Encoding properties; 。下面的bean也是一样
二.因此我们可以有个小结(其他xxxxAutoAutoConfiguration类也是这种模式):
对于HttpEncodingAutoConfiguration这个类,在通过了各类条件(@ConditionalOnWebApplication,@ConditionalOnClass,@ConditionalOnProperty)判断以后,再通过属性的绑定(@EnableConfigurationProperties({HttpProperties.class})),最终加载到容器中(@Bean) ,其相关属性可以通过配置文件进行修改,例如:
spring.http.encoding.charset=GBK
spring.http.logRequestDetails=false
具体对应HttpProperties这个类
@ConfigurationProperties(
prefix = "spring.http"
)
public class HttpProperties {
private boolean logRequestDetails;
private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();
public HttpProperties() {
}
public boolean isLogRequestDetails() {
return this.logRequestDetails;
}
public void setLogRequestDetails(boolean logRequestDetails) {
this.logRequestDetails = logRequestDetails;
}
public HttpProperties.Encoding getEncoding() {
return this.encoding;
}
public static class Encoding {
public static final Charset DEFAULT_CHARSET;
private Charset charset;
private Boolean force;
private Boolean forceRequest;
private Boolean forceResponse;
private Map mapping;
三.小扩展
上面我们说了,自动配置的生效需要经过很多条件判断@xxConditionaxx.那么我们如何知道,在SpringBoot启动的时候,哪些自动配置生效了?哪些没有生效?
我们通过在配置文件加上 debug=true
然后我就可以再控制台看到打印如下:
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:(自动配置类启用的)
-----------------
DispatcherServletAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
Negative matches:(没有启动,没有匹配成功的自动配置类)
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)