Springboot自动配置原理
2021-03-30 00:28
标签:应用 miss run 参数 策略 文件映射 关键字 ssl ati 需要先创建SpringApplication,再依据Environment创建出ApplicaitonContext,即创建好容器后,在依据一定的注解优先级顺序实例化bean时,才会调用AutoConfigurationImportSelector的selectImports方法,读取spring.factories中的AutoConfiguration标签的自动配置类进行实例化加入容器中 @SpringBootApplication 从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。 注意:@Configuration注解的配置类有如下要求: 一、用@Configuration加载spring 1.5、配置Web应用程序(web.xml中配置AnnotationConfigApplicationContext) 二、组合多个配置类 boot.autoconfigure.EnableAutoConfiguration注解 -> @Import了一个AutoConfigurationImportSelector实例 -> AutoConfigurationImportSelector类(implement ImportSelector),实现了selectImports() 方法,用来筛选被@Import的Configuration类(减去exclude等) 可见selectImports()是AutoConfigurationImportSelector的核心函数,其核心功能就是获取spring.factories中EnableAutoConfiguration所对应的Configuration类列表,由@EnableAutoConfiguration注解中的exclude/excludeName参数筛选一遍,再由AutoConfigurationImportFilter类所有实例筛选一遍,得到最终的用于Import的configuration和exclusion。 该函数是被谁调用的呢?在org.springframework.context.annotation.ConfigurationClassParser类中被processImports()调用,而processImports()函数被doProcessConfigurationClass()调用。下面从doProcessConfigurationClass() 看起。 上面为@Import()的Spring的注释的底层实现 接着看我们EnableAutoConfiguration.class(类名)对应的值: 每一个这样的 每一个自动配置类进行自动配置功能; eg :HttpEncodingAutoConfiguration 所有在配置文件中能配置的属性都是在 我们配置时的流程: SpringBoot启动会加载大量的自动配置类 我们看我们需要的功能有没有SpringBoot默认写好的自动配置类 再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了) 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值 Springboot自动配置原理 标签:应用 miss run 参数 策略 文件映射 关键字 ssl ati 原文地址:https://www.cnblogs.com/eternal-heathens/p/13591738.html自动配置的执行流程
1. @SpringBootApplication // 由启动类的@SpringBootApplication开启自动配置
2. @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //标至该类是一个配置类,与@Configuration作用一致
@EnableAutoConfiguration //启动
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
1.1、@Configuration配置spring并启动spring容器
1.2、@Configuration启动容器+@Bean注册Bean
1.3、@Configuration启动容器+@Component注册Bean
1.4、使用 AnnotationConfigApplicationContext 注册 AppContext 类的两种方法
2.1、在@configuration中引入spring的xml配置文件
2.2、在@configuration中引入其它注解配置
2.3、@configuration嵌套(嵌套的Configuration必须是静态类)
三、@EnableXXX注解
四、@Profile逻辑组配置
五、使用外部变量
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //当SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package。
@Import(AutoConfigurationImportSelector.class) //@EnableAutoConfiguration注解是Spring Boot中配置自动装载的总开关。
public @interface EnableAutoConfiguration {
}
public class AutoConfigurationImportSelector implementsDeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
//......
@Override
publicString[] selectImports(AnnotationMetadata annotationMetadata) {
// 如果AutoConfiguration没开,返回{}
if(!isEnabled(annotationMetadata)) {
returnNO_IMPORTS;
}
// 将spring-autoconfigure-metadata.properties的键值对配置载入到PropertiesAutoConfigurationMetadata对象中并返回
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 基于各种配置计算需要import的configuration和exclusion
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
returnStringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
// 判断AudoConfiguration是否开启
protectedbooleanisEnabled(AnnotationMetadata metadata) {
if(getClass() == AutoConfigurationImportSelector.class) {
// 如果配置文件中有"spring.boot.enableautoconfiguration",返回该字段的值;否则返回true
returngetEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
returntrue;
}
protectedAutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if(!isEnabled(annotationMetadata)) {
returnEMPTY_ENTRY;
}
// 获取注解的属性值
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 从META-INF/spring.factories文件中获取EnableAutoConfiguration所对应的configurations,但并不实例化,还要筛选
List
META-INF/spring.factories
,并对相应的key值进行筛选,这里使用的key值为org.springframework.boot.autoconfigure.EnableAutoConfiguration。public static List
protected List getAutoConfigurationImportListeners() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
}
protected List getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
/**
* 通过classLoader从各个jar包的classpath下面的META-INF/spring.factories加载并解析其key-value值,然后创建其给定类型的工厂实现
*
* 返回的工厂通过AnnotationAwareOrderComparator进行排序过的。
* AnnotationAwareOrderComparator就是通过@Order注解上面的值进行排序的,值越高,则排的越靠后
*
* 如果需要自定义实例化策略,请使用loadFactoryNames方法获取所有注册工厂名称。
*
* @param factoryType 接口或者抽象类的Class对象
* @param classLoader 用于加载的类加载器(可以是null,如果是null,则使用默认值)
* @throws IllegalArgumentException 如果无法加载任何工厂实现类,或者在实例化任何工厂时发生错误,则会抛出IllegalArgumentException异常
*/
public static
xxxAutoConfiguration
类都是容器中的一个组件,都加入到容器中;用他们来做自动配置;package org.springframework.boot.autoconfigure.web.servlet;
......
//表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@Configuration(
proxyBeanMethods = false
)
/**
* 启动指定类的ConfigurationProperties功能;
* 将配置文件中对应的值和HttpProperties绑定起来;
* 并把HttpProperties加入到ioc容器中
*/
@EnableConfigurationProperties({HttpProperties.class})
/**
* Spring底层@Conditional注解
* 根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效;
* 判断当前应用是否是web应用,如果是,当前配置类生效
*/
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//判断当前项目有没有这个类
@ConditionalOnClass({CharacterEncodingFilter.class})
/**
* 判断配置文件中是否存在某个配置 spring.http.encoding.enabled;
* 如果不存在,判断也是成立的
* 即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
*/
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
//它已经和SpringBoot的配置文件映射了
private final Encoding properties;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
@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;
}
......
xxxAutoConfiguration
读取 实例化的xxxxProperties类,根据属性生成相应的bean给ApplicationContext调用。xxxxProperties
类中封装着;配置文件能配置什么就可以参照某个功能对应的这个属性类@ConfigurationProperties(
prefix = "spring.http"
)
public class HttpProperties {
private boolean logRequestDetails;
private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();
xxxxAutoConfigurartion
:自动配置类;xxxxProperties
:封装配置文件中相关属性;