springboot启动通过main方法,在main方法所在的类添加了SpringBootApplication注解
示例代码
启动类Application.class
package com.netepg;
@SpringBootApplication
public class App{
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
SpringBootApplication注解元数据
首先查看下在springboot中SpringBootApplication注解都有哪些信息
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};
/**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
注解主要包括SpringBootConfiguration、EnableAutoConfiguration、ComponentScan
1、SpringBootConfiguration注解表明当前类是配置类
image.png
2、EnableAutoConfiguration注解表示开启自动配置
3、ComponentScan表示,扫描过滤
EnableAutoConfiguration注解
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
这个注解元数据包括AutoConfigurationPackage和使用import导入了EnableAutoConfigurationImportSelector类
1、AutoConfigurationPackage注解导入AutoConfigurationPackages.Registrar类
image.png
AutoConfigurationPackages.Registrar类实现了ImportBeanDefinitionRegistrar
image.png
AutoConfigurationPackages#register
BEAN = "org.springframework.boot.autoconfigure.AutoConfigurationPackages"
把AutoConfigurationPackages注册到bean工厂,并把当前包名设置为ConstructorArgumentValues参数
image.png
实现了ImportBeanDefinitionRegistrar的类,也会在生成bean的生命周期的import过程中,调用registerBeanDefinitions方法
2、EnableAutoConfigurationImportSelector
在spring容器实例化Bean的过程中,在解析配置类时,会对实现了DeferredImportSelector的导入类调用selectImports方法
2.1、selectImports
AutoConfigurationImportSelector#selectImports
加载元数据
image.png
AutoConfigurationMetadataLoader#loadMetadata(java.lang.ClassLoader)
image.png
将会加载spring-autoconfigure-metadata.properties文件的数据。加载过程把配置文件中的值加载到Properties然后封装成AutoConfigurationMetadata对象返回
image.png
对于封装的属性配置元数据,加载META-INF/spring.factories数据
经过去除重复值,去掉需要剔除的值,经过filter过滤处理
2.2、getCandidateConfigurations
AutoConfigurationImportSelector#getCandidateConfigurations
查询带spring.factories文件的依赖包,获取所有值的键值对。通过EnableAutoConfiguration过滤出来需要自动加载的
image.png
AutoConfigurationImportSelector#getSpringFactoriesLoaderFactoryClass
表示只加载EnableAutoConfiguration类型的类
image.png
2.3、removeDuplicates
AutoConfigurationImportSelector#removeDuplicates
移除重复的通过LinkedHashSet集合接收,然后转成ArrayList
image.png
2.4、sort
对configurations集合排序 sort()
2.5、getExclusions
AutoConfigurationImportSelector#getExclusions
剔除exclude excludeName
image.png
2.6、checkExcludedClasses
checkExcludedClasses检查是否包含需要剔除的exclusions集合元素
image.png
2.7、filter
AutoConfigurationImportSelector#filter
image.png
对configurations集合中的元素通过AutoConfigurationImportFilter过滤器实现类OnClassCondition进行过滤
①、match
OnClassCondition#match
image.png
②、getOutcomes
OnClassCondition#getOutcomes
image.png
③、resolveOutcomes
分成两半调用resolveOutcomes方法
OnClassCondition.StandardOutcomesResolver#resolveOutcomes
image.png
StandardOutcomesResolver#getOutcomes
image.png
PropertiesAutoConfigurationMetadata#get(String, String,String)
image.png
拼接className和ConditionalOnClass的字符串从properties查找
StandardOutcomesResolver#getOutcomes方法返回没找到类的集合
image.png
OnClassCondition.StandardOutcomesResolver#getOutcome
image.png
image.png
image.png
image.png
所以,ConditionOutcome集合存储的是加载不到的class
根据ConditionOutcome[] outcomes集合获取是否match匹配值的集合
image.png
match是true,对不包含的进行跳过skip(true表示跳过,不包含)
image.png
image.png
对包含的元素放入到result集合并返回
image.png
2.8、fireAutoConfigurationImportEvents
AutoConfigurationImportSelector#fireAutoConfigurationImportEvents
image.png
AutoConfigurationImportSelector#invokeAwareMethods
为监听器对象ConditionEvaluationReportAutoConfigurationImportListener设置beanFactory值
image.png
ConditionEvaluationReportAutoConfigurationImportListener#onAutoConfigurationImportEvent
创建ConditionEvaluationReport用来记录评估和日志的条件评估细节类,从bean工厂获取
condition.ConditionEvaluationReport#get
beanName是autoConfigurationReport,ConditionEvaluationReport的条件评估细节类
image.png
image.png
把evaluationCandidates和exclusions集合放入当前对象的属性中
image.png
最终是放到bean工厂的singletonOjects单例对象中
image.png
并selectImports方法返回configurations集合会放入到在processImports方法成配置类ConfigurationClass中
spring.factories数据与spring-autoconfigure-metadata.properties数据对应关系
基于2.1.x
spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
对于DispatcherServletAutoConfiguration、ServletWebServerFactoryAutoConfiguration、WebMvcAutoConfiguration类需要查找对于的spring-autoconfigure-metadata.properties的值
spring-autoconfigure-metadata.properties
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration.ConditionalOnClass=org.springframework.web.servlet.DispatcherServlet
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration.ConditionalOnClass=javax.servlet.ServletRequest
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.ConditionalOnClass=javax.servlet.Servlet,org.springframework.web.servlet.config.annotation.WebMvcConfigurer,org.springframework.web.servlet.DispatcherServlet
如果能够加载org.springframework.web.servlet.DispatcherServlet类,则DispatcherServletAutoConfiguration会自动装配到bean工厂。
能够加载javax.servlet.ServletRequest,则ServletWebServerFactoryAutoConfiguration自动装配到bean工厂
ServletWebServerFactoryAutoConfiguration
查找过程与类上条件相同@ConditionalOnClass(ServletRequest.class)
image.png
加载tomcat
ServletWebServerFactoryAutoConfiguration类导入EmbeddedTomcat类,需要具有相关的类
image.png
说明:
本章源码分析是基于1.5.x
导入的类是EnableAutoConfigurationImportSelector
EnableAutoConfigurationImportSelector实现了AutoConfigurationImportSelector
2.1.x 直接导入的类是AutoConfigurationImportSelector
selectImports方法的实现过程是一样的,只是抽出了一个方法
image.png
AutoConfigurationImportSelector#getAutoConfigurationEntry
image.png
总结:
在自动装配中@ConditionalOnClass注解的使用
在自动配置SpringBootApplication注解中使用导入外部类方式:
1、实现了ImportBeanDefinitionRegistrar的类调用registerBeanDefinitions方法
2、实现了ImportSelector的类调用selectImports方法
@SpringBootApplication注解关键是如何读取数据并如何完成自动注入的
首先从所有依赖包查询spring-autoconfigure-metadata.properties文件,读取里面的数据加载到自动配置类元数据类中。
所有依赖包查询并获取spring.factories文件数据到集合中,然后经过去重,剔除处理。经过filter过滤步骤处理,会最终得到符合条件的类。
在这个关键步骤filter中,主要过程是:
1、spring.factories文件数据加载到集合的数据值拼接ConditionOnClass字段
2、对拼接后的值,在spring-autoconfigure-metadata.properties加载的自动配置类元数据类中(以键值对形式存在)。查找对应的值
3、对查找的值,通过类加载器查找是否能够加载到。返回一个match集合
4、通过match集合确定skip集合是否可以跳过
5、对于没有跳过的值,即可以通过类加载器加载的类放入到集合result中
6、selectImports方法的返回值result可以在spring bean的生命周期过程中加载这些类生成相应的bean
最终会加入到spring的bean工厂之中
最终效果是完成了springboot的自动配置
网友评论