* [三、配置加载原理源码解析](about:blank#_26)
* [四、@EnableAutoConfiguration 作用](about:blank#EnableAutoConfiguration__54)
* [五、Bean的自动装配实现原理简述](about:blank#Bean_65)
在本专栏一开始,我们就讲过Spring Boot大量的简化了配置。实际上这些配置还都存在,只是将一些不常用的配置隐藏了起来,不需要我们像以往一样逐一配置,从而减少了配置量、提高了开发效率。本文向大家介绍一下,Spring Boot实现自动配置加载的原理。
我们之前为大家介绍了,Spring Boot里面的各种Bean(类对象)能够实现自动装载,自动的装载帮我们减少了XML的配置,和手动编码进行Bean的加载工作。从而极大程度上帮我们减少了配置量和代码量。
要实现Bean的自动装载,需要解决两个问题
-
如何保证Bean自动装载的灵活性?这个问题通过配置文件来解决,在配置A情况下去装载BeanY;在配置B情况下去装载BeanZ。(通常情况下配置A和B会有默认值,来决定默认的装载行为,这样就不需要我们配置了,进一步减少配置量)
-
如何保证Bean装载的顺序性?当BeanA装载完成之后再去装载BeanY,BeanY装载完成之后才去装载BeanX。这个装载顺序问题由@ConditionOnXXXXXXX注解来解决。
SpringBoot使用一个全局的配置文件,配置文件名是固定的;
-
application.properties
-
application.yml
全局配置文件的作用:修改SpringBoot自动配置的默认值,通过配置来影响SpringBoot自动加载行为。
所有的Spring Boot应用程序都是以SpringApplication.run()作为应用程序入口的。下面我们来一步一步跟踪一下这个函数。
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
run方法传入了SpringApplication
对象和一些运行期参数。继续向前跟进,我们发现一个类叫做SpringFactoriesLoader,这里面体现了Spring Boot加载配置文件的核心逻辑。
从上图可以看到:
-
从
META-INF/spring.factories
文件夹下下面加载了spring.factories文件资源 -
然后读取文件中的ClassName作为值放入Properties。
然后通过反射机制,对spring.factories里面的类资源进行实例化,所以spring.factories文件里面究竟写了什么类?这些类是做什么的?就是我们下一步要探究的问题了。
SpringBoot入口启动类使用了SpringBootApplication,实际上就是开启了自动配置功能@EnableAutoConfiguration。
SpringFactoriesLoader会以@EnableAutoConfiguration的包名和类名org.springframework.boot.autoconfigure.EnableAutoConfiguration为Key查找spring.factories文件,并将value中的类名实例化加载到Spring Boot应用中。如下图:
spring.factories文件中的每一行都是一个自动装配类。
每一个自动配置类进行自动配置功能(spring.factories中的每一行对应的类),我们以HttpEncodingAutoConfiguration为例讲解一下:
//加载application全局配置文件内的部分配置到HttpEncodingProperties里面
@Configuration
@EnableConfigurationProperties({HttpEncodingProperties.class})
//当web容器类型是servlet的时候执行本类中的自动装配代码
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//当有一个CharacterEncodingFilter的这样一个类的字节码文件时时执行本类中的自动装配代码
@ConditionalOnClass({CharacterEncodingFilter.class})
//当spring.http.encoding配置值为enabled的时候执行本类中的自动装配代码
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true //如果application配置文件里面不配置,默认为true
)
public class HttpEncodingAutoConfiguration {
private final HttpEncodingProperties properties;
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean
//当没有CharacterEncodingFilter这个Bean就实例化CharacterEncodingFilter为一个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.HttpEncodingProperties.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.RESPONSE));
return filter;
}
@Bean
public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
}
//此处省略与自动加载无关的代码:HttpEncode的逻辑及其他
}
在配置类加载过程中,大量的使用到了条件加载注解: