Spring boot自动配置原理
自动配置,顾名思义就是不需要开发者自己去配置应用程序,而是只要满足springboot实现自动配置的条件即可。具体来说就是Springboot根据开发者添加的jar包依赖项来自动配置springboot程序的。
1.环境
spring-boot 1.5.9.RELEASE
2.配置类注册到IOC容器的流程图
3.从代码开始分析
3.1、启动类
@SpringBootApplication
public class SpringbootLearnApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootLearnApplication.class, args);
}
}
3.2、@SpringBootApplication注解
//省略部分注解
@SpringBootConfiguration//表示这是SpringBoot的配置类
@EnableAutoConfiguration//这个注解的作用就是让SpringBoot开启自动配置
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)//开启组件扫描
public @interface SpringBootApplication
@SpringBootApplication是一个组合注解,其中@EnableAutoConfiguration开启了自动配置功能。
3.3、@EnableAutoConfiguration注解
//省略部分注解
@AutoConfigurationPackage//添加该注解的类所在的package作为自动配置package进行管理
@Import({EnableAutoConfigurationImportSelector.class})//利用EnableAutoConfigurationImportSelector给容器中导入一些组件
public @interface EnableAutoConfiguration
EnableAutoConfigurationImportSelector类继承AutoConfigurationImportSelector类,查看AutoConfigurationImportSelector类源代码
public String[] selectImports(AnnotationMetadata annotationMetadata) {
....
//获取候选的配置
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
....
}
getCandidateConfigurations方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
....
}
3.4、SpringFactoriesLoader类的loadFactoryNames方法
SpringFactoriesLoader类的loadFactoryNames方法,扫描所有jar包类路径下 META-INF/spring.factories 把扫描到的这些文件的内容包装成properties对象 从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}
3.5、spring.factories在spring-test-autoconfigure下的示例
# AutoConfigureCache auto-configuration imports
org.springframework.boot.test.autoconfigure.core.AutoConfigureCache=\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
# AutoConfigureDataJpa auto-configuration imports
org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa=\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
.......
4.HttpEncodingAutoConfiguration自动配置过程
4.1、HttpEncodingAutoConfiguration
@Configuration //配置类,可以给容器中添加组件
@EnableConfigurationProperties({HttpEncodingProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication//当Spring服务为web时,才使注解的类生效
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)//判断配置文件中是否存在某个配置spring.http.encoding.enabled;如果不存在,判断也是成立的,即使在配置文件中不配置spring.http.encoding.enabled=true,配置也是生效的
public class HttpEncodingAutoConfiguration {
//HttpEncoding的配置类,其中字段已经和配置文件映射了
private final HttpEncodingProperties properties;
//当前构造函数参数的值,会从容器中获取
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean//给容器中添加一个组件CharacterEncodingFilter
@ConditionalOnMissingBean({CharacterEncodingFilter.class})//判断容器有没有这个组件
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;
}
HttpEncodingAutoConfiguration会根据当前不同的条件判断,决定这个配置类是否生效,如果这个配置类生效,会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
4.2 、HttpEncodingProperties
@ConfigurationProperties(prefix = "spring.http.encoding")////从配置文件中获取指定的值和bean的属性进行绑定
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Charset charset = DEFAULT_CHARSET;
private Boolean force;
private Boolean forceRequest;
private Boolean forceResponse;
private Map<Locale, Charset> mapping;
public Charset getCharset() {
return this.charset;
}
.....
}
4.3、总结
- SpringBoot启动会加载大量的自动配置类;给容器中自动配置添加组件的时候,会从
propeties
类中获取配置文件中指定这些属性的值 - xxxxAutoConfigurartion:⾃动配置类给容器中添加组件;
- xxxxProperties:封装配置文件中相关属性;
小技巧:
在配置文件中配置:debug=true,可以在控制台打印自动配置报告。