Spring Boot 启动源码分析

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 的定义,可以看看具体的实现。

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/convict_eva/article/details/80068076
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞