spring boot 项目都有个启动类,如下:
@SpringBootApplication
public class DemoApplication{
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
写在前面:
自动配置的类的加载和配置:
SpringFactoriesLoader.loadFactoryNames() 方法加载所有的META-INF/spring.factories 文件,这个文件就是配置要自动配置的类。
文件的配置包含了:ApplicationListener, ApplicationContextInitializer,AutoConfigurationImportFilter,EnableAutoConfiguration 等等,可以自己去看一下。
这个文件就是 spring-boot-autoconfigure-1.5.9.RELEASE.jar!/META-INF/spring.factories
1、SpringApplication.run() 方法:
跟踪到实现:
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
/先new 一个SpringApplication 对象,然后调用run 方法。
return (new SpringApplication(sources)).run(args);
}
1.1 创建new SpringApplication(sources) 对象:
public SpringApplication(Object... sources) {
//初始化
this.initialize(sources);
}
//初始化 initialize(sources)
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//通过"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" 这两个类是是否存在
//创建一个WebApplicationContext还是一个标准的Standalone 应用的ApplicationContext类型
this.webEnvironment = this.deduceWebEnvironment();
//通过SpringFactoriesLoader 在classpath 中查找并加载所有可用的 ApplicationContextInitializer的class
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//通过SpringFactoriesLoader 在classpath 中查找并加载所有可用的 ApplicationListener的class
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//推判出main 方法的启动类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
2、 SpringApplication 创建后就调用了 run 方法:
public ConfigurableApplicationContext run(String... args) {
//监控每个任务执行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
//设置Headless模式,默认为true
configureHeadlessProperty();
//查找通过 SpringFactoriesLoader 加载的所有 SpringApplicationRunListener 类,并调用starting 方法
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
////封装启动参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备运行环境,配置当前Spring Boot 应用将要使用的environment,在方法中调用configureEnvironment() 装载PropertySource 和 Profile
//并在此方法中调用所有 listeners 的environmentPrepared方法,通知当前SpringBoot 的Environment 装备好了。
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//加载打印的Banner
Banner printedBanner = printBanner(environment);
//根据初始化是否是webEnvironment,创建相应的ApplicationContext
context = createApplicationContext();
//异常处理
analyzers = new FailureAnalyzers(context);
//准备 ApplicationContext
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
//这个就是调用ApplicationContext的refresh 方法,这个很熟悉吧,就是spring 的 Ioc
//最后调用了 ConfigurationClassParser.processDeferredImportSelectors() 方法,是加载 selectors 的。可以通过debug 找调用链
//通过调用解析 @SpringBootApplication 注解的@Import 元注解的导入类,并调用 selectImports 方法
refreshContext(context);
//执行ioc 容器中的 ApplicationRunner 和 CommandLineRunner 的run 方法,可以自己定义这两个类的子类,在加载完后自动调用
afterRefresh(context, applicationArguments);
//调用所有的 SpringApplicationRunListeners ,告知启动完了
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
return context;
}catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
下面就对准备ApplicationContext 和 @Import 的导入类进行分析
准备ApplicationContext 方法处理过程:
//准备ApplicationContext
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置环境,资源applicationContext 的类加载器,把生成beanName 的类( BeanNameGenerator )注入到上下文
context.setEnvironment(environment);
//对ApplicationContext 进一步加工
//BeanNameGenerator 注入
//resourceLoader和calssLoader 设置
postProcessApplicationContext(context);
//使用 SpringFactoriesLoader 加载的所有 ApplicationContextInitializer,对ApplicationContext 进一步设置
applyInitializers(context);
//调用所有的 SpringApplicationRunListener 的contextPrepared 方法,告知上下文已经准备好
listeners.contextPrepared(context);
//日志处理
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//源码注释: Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
//注册banner
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
//把当前的source(当前的启动类,也可以是想让注入的类)注入到spring 容器,并且通过source 注解的信息获取元数据。
load(context, sources.toArray(new Object[sources.size()]));
//调用所有的 SpringApplicationRunListeners contextLoaded 方法,告知applicationContext 已经装填完毕
listeners.contextLoaded(context);
}
//load 方法:
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
//创建 BeanDefinitionLoader, 包含了 AnnotatedBeanDefinitionReader XmlBeanDefinitionReader ClassPathBeanDefinitionScanner 提供各种情况的 bean 读取方式
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
//加载的方法
loader.load();
}
//loader.load();
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
//启动时使用的这个加载方式
return load((Class<?>) source);
}
if (source instanceof Resource) {
//从 resource 加载
return load((Resource) source);
}
if (source instanceof Package) {
//从包加载,就是scanner扫描
return load((Package) source);
}
if (source instanceof CharSequence) {
//从string 加载
return load((CharSequence) source);
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
//load(class) 方法
private int load(Class<?> source) {
if (isGroovyPresent()) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
}
if (isComponent(source)) {
//这个才是实现的方法,一层一层往下找,最后找到的是 annotatedReader.registerBean() 方法
this.annotatedReader.register(source);
return 1;
}
return 0;
}
/**
* Register a bean from the given bean class, deriving its metadata from class-declared annotations.
* 翻译下:从给定的bean class 注册这个bean,通过这个class 定义的annotations 获取这个bean的元数据。这下很明白了,@SpringBootApplication 相关注解就是在这解析的。
*/
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
//创建注解的BeanDefinition,构造方法中创建了一个StandardAnnotationMetadata,用来存放annotatedClass 的注解
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//通过 Conditional 判断是否不加载元数据
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//解析元数据的scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
//bean 名称,就是启动类的bean demoApplication
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//metadata 的底层元素是否有Lazy Primary DependsOn Role Description 等注解或者元注解,如果有则set 相关属性(请看源码)
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
//注入bean时,
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
//创建 BeanDefinitionHolder,这个通过beanName aliases 持有bean
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//申请一个 definitionHolder 的代理对象,
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//把beanDefinition 放入到spring 容器中
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
ApplicationContext 准备完毕后,就调用Spring启动时调用的refreshContext(context) 方法,自动配置的类就在这里面被调用的。
@SpringBootApplication 注解的@Import 元注解的导入类,并调用 selectImports 方法
//autoConfiguration 方法,参数就是启动类 DemoApplication 的注解
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//没有自动配置的就返回
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
// META-INF/spring-autoconfigure-metadata.properties 并把这个文件的配置Properties成,然后创建 PropertiesAutoConfigurationMetadata 对象并返回
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
//annotationMetadata 的属性,这里就是把 @SpringBootApplication 注解的exclude 值,解析出来。
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 使用classLoader 加载所有的 META-INF/spring.factories 文件,并从中解析出 EnableAutoConfiguration.class 子类。 //是使用SpringFactoriesLoader.loadFactoryNames() 方法,在前面加载 applyInitializers 也是使用同样方法,只是解析的类不一样。
List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
//去重
configurations = removeDuplicates(configurations);
//排序,先按照字母表顺序排,再按照 order 注解顺序排,最后处理 @AutoConfigureBefore @AutoConfigureAfter 注解1
configurations = sort(configurations, autoConfigurationMetadata);
//获取到 annotationMetadata 属性排除加载的的类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//如果排除的类存在,且不在 configurations 集合中,那么就要 IllegalStateException 运行时异常
checkExcludedClasses(configurations, exclusions);
//删除掉忽略自动配置的类
configurations.removeAll(exclusions);
//过滤掉不用自动配置的类。这个filter 方法就是我们自己配置的 Condition matchs() 方法调用的地方
configurations = filter(configurations, autoConfigurationMetadata);
//开始自动配置
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
//过滤掉不用怎么配置的类,返回的是要自动配置的
private List<String> filter(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
//自动配置类全类名
String[] candidates = configurations.toArray(new String[configurations.size()]);
//自动配置的类是否要跳过自动配置
boolean[] skip = new boolean[candidates.length];
//如果有跳过自动配置的,那么就是true了,如果所有的自动配置类都匹配上了,那么就是false,就可以快速返回,不用把不用自动配置的类过滤掉
boolean skipped = false;
//通过pringFactoriesLoader.loadFactories() 获取 AutoConfigurationImportFilter 对象,所有的candidates 都要通过filter 过滤一遍,找出确定要自动配置的类
//getAutoConfigurationImportFilters() 方法,就是SpringFactoriesLoader.loadFactories() 方法加载所有 AutoConfigurationImportFilter.class 的类
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
//设置resource, classLoader 属性
invokeAwareMethods(filter);
//这个方法就是调用 Condition match() 方法的地方
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
skipped = true;
}
}
}
//如果所有的配置都没有跳过自动配置,那么直接返回
if (!skipped) {
return configurations;
}
//下面的代码就是把不用自动配置的类去掉,剩下的类都是要自动配置的
List<String> result = new ArrayList<String>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
+ " ms");
}
return new ArrayList<String>(result);
}
//来看看filter.match() 方法是怎么匹配的实现。 在spring.factories 配置中只配置了一个AutoConfigurationImportFilter 类OnClassCondition。即调用这个类的 match()方法。
@Override
public boolean[] match(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
//获取条件判断的类
ConditionEvaluationReport report = getConditionEvaluationReport();
//把全类名,转化成 ConditionOutcome 对象。在这个转化中处理match的
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
boolean[] match = new boolean[outcomes.length];
for (int i = 0; i < outcomes.length; i++) {
//判断是否匹配
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
if (!match[i] && outcomes[i] != null) {
logOutcome(autoConfigurationClasses[i], outcomes[i]);
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
}
}
}
return match;
}
//把自动配置的全类名转化成ConditionOutcome对象,并验证是否要自动配置
private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
//把 autoConfigurationClasses 分成两部分来处理。
// Split the work and perform half in a background thread. Using a single
// additional thread seems to offer the best performance. More threads make
// things worse
int split = autoConfigurationClasses.length / 2;
OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split, autoConfigurationMetadata);
OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split, autoConfigurationClasses.length,autoConfigurationMetadata, this.beanClassLoader);
//把自动配置的全类名转化成ConditionOutcome对象,这里看OnClassCondition内部类StandardOutcomesResolver.resolveOutcomes() 方法
ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
//合并处理完成后的结果
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
return outcomes;
}
//resolveOutcomes() 方法调用下面两个方法实现的
private ConditionOutcome[] getOutcomes(final String[] autoConfigurationClasses,
int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
for (int i = start; i < end; i++) {
String autoConfigurationClass = autoConfigurationClasses[i];
//获取自动配置类的 ConditionalOnClass 注解属性的值,即如果要自动配置,那么就要有这些类的存在。
Set<String> candidates = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnClass");
if (candidates != null) {
//如果有 ConditionalOnClass 属性配置,那么就验证是否有这些类的存在。
outcomes[i - start] = getOutcome(candidates);
}
}
return outcomes;
}
private ConditionOutcome getOutcome(Set<String> candidates) {
try {
//通过MatchType.MISSING 方法进行验证 candidates 类是否有不存在的,如果有不存在的,那么就返回ConditionOutcome.noMatch(false,"message") 对象。到这里就完成了。
List<String> missing = getMatches(candidates, MatchType.MISSING,this.beanClassLoader);
if (!missing.isEmpty()) {
return ConditionOutcome.noMatch(
ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class", "required classes")
.items(Style.QUOTE, missing));
}
}
catch (Exception ex) {
// We'll get another chance later
}
return null;
}
这里只看了ConditionalOnClass 的match() 方式,还有其它的match() ,可以自己查看。
spring-boot-autoconfigure-1.5.9.RELEASE.jar org.springframework.boot.autoconfigure.condition 包中还有很多 conditional 的定义,可以看看具体的实现。