Spring Boot源码解析

前言

        本章内容,主要会带大家了解下Spring Boot自动注入原理,以及相对于Spring有哪些细节上的改变,不了解Spring源码的同学建议先去了解下,才比较好理解本文

项目结构

首先看下项目结构图(这是我测试用的一个项目,不必纠结奇怪的文件路径)

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>javaTopython</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <java.version>11</java.version>
  </properties>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
  </parent>

  <dependencies>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <!--web起步依赖-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.58</version>
    </dependency>
  </dependencies>

</project>

配置文件 (application.yml)

server:
  port: 8888
spring:
  application:
    name: TestServer

启动文件(ServerApplication.java)

package com.zzw.rpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;

@SpringBootApplication
@Configuration
public class ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }

}

第一节:

SpringApplication对象初始化

        我们以 SpringApplication.run(ServerApplication.class); 作为入口解析源码,点进去我们会追到这么几段

SpringApplication.run(ServerApplication.class, args); ->
return run(new Class<?>[] { primarySource }, args); ->
return new SpringApplication(primarySources).run(args);

        这其中primarySource就是我们的ServerApplication类(启动类),第一节我们主要来了解下new SpringApplication(primarySources)都做了哪些事情

        跳过重载直接来看方法

SpringApplication

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // 设置资源加载器(这时应该时空的)
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
        // 设置启动类(后续流程会用到)
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 判断下当前应用类型
		this.webApplicationType = deduceWebApplicationType();
        // 【重点】加载初始化器
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
        // 加载监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

         我们只看判断应用类型 和 加载初始化器的逻辑,监听器加载同初始化器一样可自行翻阅,这里须格外注意初始化器加载过程,因为其关系到自动注入。(本质上这个逻辑相当于SPI机制的变种实现)

deduceWebApplicationType()

	private WebApplicationType deduceWebApplicationType() {
        // 当前存在DispatcherHandler 且不存在 DispatcherServlet
		if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
				&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
        // 不包含ConfigurableWebApplicationContext 和 Servlet类
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
        // 否则就是SERVLET类型的应用
		return WebApplicationType.SERVLET;
	}

        至于ClassUtils.isPresent(className, null) 方法不必过多纠结,其本身就是AppClassLoader加载下类,看能不能加载到,我们案例里返回的就是WebApplicationType.SERVLET;

        当设置完应用类型后,进行初始化器加载

getSpringFactoriesInstances(Class<T> type)

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
        // 获取类加载器
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// 加载springFactories配置文件,得到初始化器名称列表(这个方法及其重要,后续会反复遇到)
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        // 加载出实例
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
        // 对初始化器进行排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

SpringFactoriesLoader.loadFactoryNames

	public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        // org.springframework.context.ApplicationContextInitializer
		String factoryClassName = factoryClass.getName();
        // 加载spring.factories文件 获取初始化器名称列表
		return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
	}

loadSpringFactories(@Nullable ClassLoader classLoader)

	private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        // 先获取下有没有加载过对应资源(第一次来 当然是没加载过)
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
            // 加载spring.factories文件
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					List<String> factoryClassNames = Arrays.asList(
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
					result.addAll((String) entry.getKey(), factoryClassNames);
				}
			}
            // 中间那一段不必要扣,就是加载文件解析文件
            // 将解析结果加入缓存 下次来直接用
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

这里示例下spring.factories文件(有多个这里只列出一个)

spring.factories

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

# Failure AnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

最终加载出的结果如图所示

以上加载spring.factories的过程就结束了,我们回到获取初始化器名称列表的位置

loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
// loadSpringFactories(classLoader)返回的如上图所示个map,此时factoryClassName是
// org.springframework.context.ApplicationContextInitializer
// 那我们最终获取到了六个初始化器

根据初始化器名称加载初始化器示例完毕后,回到SpringApplication初始化部分

SpringApplication

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        *******
        // getSpringFactoriesInstances已经取出了初始化器实例对象
        // setInitializers 仅将刚获取到的六个初始化器赋值给SpringApplication.initializers属性
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
        // 加载监听器(流程同上) 监听器赋值给listeners对象
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 设置启动类(从方法栈中找到切入点为main的类 不必细看 了解即可)
		this.mainApplicationClass = deduceMainApplicationClass();
	}

deduceMainApplicationClass[了解即可不必细看]

	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}

第二节:

SpringApplication.run方法

        在SpringApplication对象初始化完成之后,既要进行run方法的调用,接下来先看下具体流程,重点的方法会进行标注

public ConfigurableApplicationContext run(String... args) {
        // 记录程序运行时间
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
        // Spring上下文对象(这里和Spring源码的逻辑有些不同)
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        // 一些外设的系统配置 不重要,不关心
		configureHeadlessProperty();
        // 【1.获取并启动监听器】这里拿的是事件的发布者,而不是Application初始化的监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
        // 发送一个初始化事件
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
            // 【2.准备环境对象】
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
            // 处理需要忽略的bean
			configureIgnoreBeanInfo(environment);
            // 打印日志提示(>_< Spring Boot 的提示就搁这步打出来的)
			Banner printedBanner = printBanner(environment);
            // 【3.初始化应用上下文对象】
			context = createApplicationContext();
            // 实例化SpringBootExceptionReporter
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
            // 【4.刷新应用上下文前的准备阶段】
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
            // 【5.刷新应用上下文】
			refreshContext(context);
            // 【6.刷新应用上下文后置的拓展接口】
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

需要重点关注的方法已经使用【】标记过了,接下来就逐一对其进行分析

1.获取并启动监听器

        事件的发布机制贯穿了SpringBoot整个生命周期,就从获取事件发布者 及 starting事件来说明这个流程

// 【1.获取并启动监听器】这里拿的是事件的发布者,而不是Application初始化的监听器
SpringApplicationRunListeners listeners = getRunListeners(args);

getRunListeners

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        // 获取事件发布者 SpringApplicationRunListener 
        // 想必细心的读者已经发现getSpringFactoriesInstances这个方法很眼熟了,没错初始化时 获取监听器列表和初始化器列表用的就是这个方法
        // 获取出来的监听器 会赋值给SpringApplicationRunListeners的listeners属性,这里就不特意列出代码了
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

发送事件starting()

listeners.starting();

// 这里我们获取到的 SpringApplicationRunListener 只有一个 EventPublishingRunListener
// 它的starting方法是通过 广播器 表里得到对事件感兴趣的监听器进行事件发送

// 1.广播器进行广播(构建StartingEvent事件对象)
this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));

// 2.根据事件类型获取对应的监听器并执行
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    // 获取事件类型 这里的事件类型是StartingEvent
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 这里是根据事件类型获取到感兴趣的监听器 并进行执行(执行器这里并不涉及 所以不展开 感兴趣可以自行了解下)
    // 获取到了四个监听器 这里我们用LoggingApplicationListener 举例
	for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        // 没设置 获取不到 不关心
		Executor executor = getTaskExecutor();
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
            // 拿着监听器和事件进行执行动作
			invokeListener(listener, event);
		}
	}
}

// 3.执行onApplicationEvent方法,由于监听器都继承了ApplicationListener接口 所有都有这个方法
public void onApplicationEvent(ApplicationEvent event) {
    // 这个方法在做什么并不重要,重要的是这里是监听器里的逻辑,我们看到这就可以了事件就发布完毕了,如果对各个监听器的作用好奇,可挨个追进去看一看
	if (event instanceof ApplicationStartingEvent) {
		onApplicationStartingEvent((ApplicationStartingEvent) event);
	}
	else if (event instanceof ApplicationEnvironmentPreparedEvent) {
		onApplicationEnvironmentPreparedEvent(
				(ApplicationEnvironmentPreparedEvent) event);
	}
	else if (event instanceof ApplicationPreparedEvent) {
		onApplicationPreparedEvent((ApplicationPreparedEvent) event);
	}
	else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event)
			.getApplicationContext().getParent() == null) {
		onContextClosedEvent();
	}
	else if (event instanceof ApplicationFailedEvent) {
		onApplicationFailedEvent();
	}
}

 我们闪回下,初始化SpringApplication对象时 我们获取到的监听器列表如下

starting事件所获取到的监听器列表如下

        有一部分细心且求知欲强的朋友可能注意到了,初始化监听器的时候,是赋值给SpringApplication,但是发布事件的时候确是从广播器SimpleApplicationEventMulticaster中获取的,那广播器是什么时候加载的呢。

ok 让我们找到广播器加载的位置看一下

事件发布者构造方法

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
        // 在这!!
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

        那现在的问题就是,EventPublishingRunListener是什么时候创建的,我们大胆的猜测下,还记得getRunListeners(args);在做什么吗,就是在获取这个发布者,在这里及创建了EventPublishingRunListener实例,同时传入了SpringApplication进行赋值,接下来我们验证下

        断点打在初始化方法赋值的位置 来看堆栈信息,我们能看到,确实是这样的,大家领会精神,这部分代码并不大重要,感兴趣跟着思路追下即可

2.准备环境对象

回到我们的主线上来,准备环境对象

// 【2.准备环境对象】
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

// 环境对象中会加载一些系统环境变量,但是我们不必关心,重点看发送环境对象准备事件的发送
private ConfigurableEnvironment prepareEnvironment(
		SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 发送环境准备事件
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (this.webApplicationType == WebApplicationType.NONE) {
		environment = new EnvironmentConverter(getClassLoader())
				.convertToStandardEnvironmentIfNecessary(environment);
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

listeners.environmentPrepared(environment);事件所获取到的监听器如下

        这里我们关注ConfigFileApplicationListener这个监听器,应为它涉及到配置文件的加载,加载的逻辑暂与boot启动流程关系不大,不详细去看,我们只看下加载配置文件时的顺序

直接列出图来说服力不大,我们可以直接看环境对象中配置文件的加载顺序

        备注: 同一目录下,有yml也有properties会先读取properties,同一属性如在多个配置文件中配置,则会使用第一个读到的

        如果记不住顺序,直接来找这个环境对象验证即可,这也是读源码的乐趣,我们知其然,也知其所以然        

3.初始化上下文对象

这一步创建了上下文对象ApplicationContext 以及 beanFactory

// 初始化上下文对象
context = createApplicationContext();
	protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
                // 获取下当前应用类型(SpringApplication对象初始化的时候确定的 此时是SERVLET)
				switch (this.webApplicationType) {
				case SERVLET:
                    // DEFAULT_WEB_CONTEXT_CLASS = 
                    // org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
					contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
        // 这里就是根据class生成实例类了 contextClass = AnnotationConfigServletWebServerApplicationContext 该类继承关系如下
        // AnnotationConfigServletWebServerApplicationContext -> 
        // ServletWebServerApplicationContext ->
        // GenericWebApplicationContext ->
        // GenericApplicationContext
        // 在GenericApplicationContext的构造中 创建一个beanFactory
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

GenericApplicationContext构造方法

    // 后续Spring代码refresh方法中,不会在新建beanFactory,而是使用这个
    public GenericApplicationContext() {
        this.customClassLoader = false;
        this.refreshed = new AtomicBoolean();
        this.beanFactory = new DefaultListableBeanFactory();
    }
拓展一 这里在给出一个拓展知识,可看可不看

        我们的启动类上标注了一个组合注解@SpringBootConfiguration,它包含import @Configuration等等,那这些注解是在什么时候解析的呢,又是怎样解析的呢,在下文大家会看到解析流程是通过BeanFactoryPostProcessors这个类型的后置处理器解析的,具体的类叫做ConfigurationClassPostProcessor,它就是在初始化上下文对象的时候进行的Bean定义注册,我们到AnnotationConfigServletWebServerApplicationContext(这个是上下文对象哈)的构造中看下

备注: 只看有注释的地方就行别纠结细节

	public AnnotationConfigServletWebServerApplicationContext(
			DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
        // 就是这里 继续往下看
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        // 注册后置处理器
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

最终到这个方法中

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
    ***************
    // 判断现在是否用名为org.springframework.context.annotation.internalConfigurationAnnotationProcessor的Bean定义
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            // 没有的话创建一个ConfigurationClassPostProcessor类型的
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
            // 注册Bean定义
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
    ***************
 }

4.刷新应用上下文前的准备阶段

        这个方法主要是进行了属性赋值、执行初始化器、发送上下文准备事件、加载启动类等动作,这里主要关注启动类加载动作即可

刷新应用上下文前的准备阶段

	private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
        // 赋值环境对象
		context.setEnvironment(environment);
        // 前置处理上下文对象(注册一些Bean定义 设置一些属性)
		postProcessApplicationContext(context);
        // 执行初始化器(添加了两个后置处理器)
		applyInitializers(context);
        // 发送容器刷新准备事件
		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) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// 加载资源(SpringApplication初始化时 我们传进来的启动类class)
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
        // 加载启动类(后续要用 以加载启动类上的注解 @SpringBootApplication 组合注解)
		load(context, sources.toArray(new Object[0]));
		listeners.contextLoaded(context);
	}

        针对load方法,经过一系列的重载,最终会调用到doRegisterBean,将启动类包装为Bean定义注册在BeanFactory.beanDefinitionMap中 如图所示(这里知道它咋来的就行了)

5.刷新应用上下文

        refreshContext(context);方法向下追 会进入到Spring的refresh方法 如下,但这里与Spring源码中的不完全一致

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
            
			/* 【1.准备刷新】*/
			prepareRefresh();

			/* 【2.初始化 新BeanFactory】在这之前BeanFactory已经初始化完毕了*/
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			/* 【3.bean工厂前置操作】*/
			prepareBeanFactory(beanFactory);

			try {
				// 【4.bean工厂后置操作】 后置处理器 BeanFactoryPostProcessor 
				postProcessBeanFactory(beanFactory);

                // 【5.调用bean工厂后置处理器】 重点
				invokeBeanFactoryPostProcessors(beanFactory);

				// 【6.注册Bean后置处理器】只注册不调用
				registerBeanPostProcessors(beanFactory);

				// 【7.初始化消息源】国际化问题i18n
				initMessageSource();

				// 【8.初始化事件广播器】
				initApplicationEventMulticaster();

				// 【9.拓展方法】
				onRefresh();

				// 【10.注册监听器】
				registerListeners();

				// 【11.实例化所有剩余(非懒加载)单例】 重点
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

        我们直接从第五步调用bean工厂后置处理器开始看起(前面四个步骤 除beanFactory外 过程都和Spring差不多 不特别讲述)

BeanFactoryPostProcessors调用 重点

        对应后置处理器的查询和调用逻辑,与Spring中一致,但要注意ConfigurationClassPostProcessor类型的后置处理器,这个后置处理器中进行了@ComponentScan | @Import | @Configuration | @Bean等等注解的解析(BeanFactoryPostProcessors的加载时机可 拓展一 查看)

        这里主要看启动类的解析,在进行源码解析前,我们自己创建一个配置类

MyConfig

@Configuration
public class MyConfig {

    @Bean(name = "token")
    public String getToken(){
        return "TESTTOKEN";
    }

}

然后来看下流程图

@ComponentScan注解解析

        这里的方法都比较长,只列出关键位置的代码,暂时不重要的代码 ***** 略过

        首先明确下位置,我们现在位于ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法

// 这里的入参registry 是 BeanFactory
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取下所有BeanDefinition
String[] candidateNames = registry.getBeanDefinitionNames();

for (String beanName : candidateNames) {
    BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
        if (logger.isDebugEnabled()) {
            logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
        }
    }
    else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
        // 如果该Bean定义存在@Configuration(这里这样理解就可以 其实不止) 包装下Bean定义添加到待处理列表
        configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    }
}

***************

// 创建一个 @Configuration 注解的解析对象
ConfigurationClassParser parser = new ConfigurationClassParser(
    this.metadataReaderFactory, this.problemReporter, this.environment,
    this.resourceLoader, this.componentScanBeanNameGenerator, registry);

// 待处理列表中目前只有启动类 ServerApplication
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
    parser.parse(candidates);
    // 不是说下面没用 只是太多影响看 后续回到这里在具体来看
   **********
   }while (!candidates.isEmpty());
}

        上面这段,取到了启动类的Bean定义,创建了@Configuration的解析对象,接下来就要进行实际解析了

因为我们是注解驱动 所以会到这个方法

	protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
        // 这里是根据Bean定义元数据生成了ConfigurationClass对象
        // 这个对象中会存储 类似与 @Bean方法 @Import对象 等等,到@Configuration解析完毕后,会同一再次解析这些ConfigurationClass生成对应Bean定义
		processConfigurationClass(new ConfigurationClass(metadata, beanName));
	}

往下跟代码 我们会走到如下方法中,这个方法很重要

// 此时我们解析的还是启动类
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {

    // Recursively process any member (nested) classes first
    processMemberClasses(configClass, sourceClass);

    // 启动类没标注PropertySources 所以进不来
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
       ******************************
    }

    // 获取componentScan注解 启动类有 可以进来
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() &&
        !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        for (AnnotationAttributes componentScan : componentScans) {
            // 拿着componentScan对象(解析注解获得的) 以及启动类 开始扫描获取标注@Component的Bean
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
            this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // 遍历获取到的Bean定义(这些Bean定义都有 @Component注解)
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    // 递归处理(因为查出来的Bean 也可能标注了)
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    // 后面也很重要 但是启动类componentScans解析先看到这里哈 **********************************
}
// 这个方法主要就是根据 componentScan注解 中的属性 进行赋值 以及进行component的扫描
// 主要看有注释的地方就可以
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    // 创建一个扫描器
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                                                                                componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

***************************************************************

    Set<String> basePackages = new LinkedHashSet<>();
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                                                               ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    
    // 如果没指定扫描路径 则设置启动类所在包为扫描路径(这就是为什么默认扫描启动类所在包及其子包)
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }
        
*******************************************************************
    // 添加一个过滤器
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
			@Override
			protected boolean matchClassName(String className) {
                // 后续检查待处理@Component的时候就不会处理引导类了
				return declaringClass.equals(className);
			}
		});

    // 开始扫描
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}
// 此时扫描路径便是我们的启动类所在 ["com.zzw.rpa"]
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // 构建返回值列表
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 扫描出包路径下所有标注 @component 的资源(已处理过的除外 这里是启动类除外)
        // 当前项目资源有 MyConfig.class & TestController.class (扫描过程 下方单独列出)
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        // 遍历查询到的Bean定义
        for (BeanDefinition candidate : candidates) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            // 检查下是否注册过该Bean定义了
            if (checkCandidate(beanName, candidate)) {
                // 包装下
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // 注册Bean定义(这里可以debug看下 BeanFactory中的bean定义)
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

@component资源扫描过程

// 从findCandidateComponents方法一路下追
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
            // 拼出资源路径 这里就是我们上方默认的启动文件路径
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            // 根据路径加载所有资源文件
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
                        // 加载资源文件
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        // 判断资源未见是否是 待处理的@Component
						if (isCandidateComponent(metadataReader)) {
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
                            // 判断资源未见是否是 待处理的@Compnoent
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
                                // 添加进待处理列表(也就是我们获取到的@Component对象列表)
								candidates.add(sbd);
                                // 下面还有内容 但不重要 给省略了*********************
							}
						}
					}
				}
			}
		}
		return candidates;
	}

根据启动路径加载出来的资源文件Resource[] resources如下

资源待处理判断

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    // 这里是检测是否处理过了该类 如果处理过就跳过
    // 目前检查出来的三个资源会跳过引导类
    // 感兴趣检查逻辑 全文搜索下scanner.addExcludeFilter 看下
    for (TypeFilter tf : this.excludeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
        }
    }
    // 判断当前资源是不是 待处理的@Component类
    for (TypeFilter tf : this.includeFilters) {
        // 检查当前类上是否标注了@Component注解
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            // 这是检查下当前资源是否标注@Conditional注解,我们没标注 所以会返回true
            return isConditionMatch(metadataReader);
        }
    }
    return false;
}

最终筛选出来的@Component类 candidates 有 MyConfig & TestController两个

递归调用

回到引导类解析逻辑

// 
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
    ***************************************************
            // 扫@Component类就是从这进来的还记得吗
            // 那现在scannedBeanDefinitions 就是 MyConfig & TestController两个
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
            this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // 遍历获取到的Bean定义(这些Bean定义都有 @Component注解)
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                // 检查下该Bean定义是否标注了@Configuration注解 如果是 则进行递归调用
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    // 递归处理(因为查出来的Bean 也可能标注了)
                    // MyConfig是标注了 以下注解 可以进入递归
                    // @Configuration
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
    ***************************************************
}

递归解析逻辑

	protected final void parse(@Nullable String className, String beanName) throws IOException {
		Assert.notNull(className, "No bean class name for configuration class bean definition");
		MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
        // 这个方法已经进入过一次了 第一次是引导类 但这次解析的是 MyConfig类
		processConfigurationClass(new ConfigurationClass(reader, beanName));
	}
// 一路向下我们又来到了这个方法 在引导类 我们主要关注了 @Component 的解析 这次仅关注 @Bean的解析
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
    ***************************************************************
    	// 扫描本类中所有标注@Bean的方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
            // 将其添加到 本configClass的 BeanMethod列表中(注意这时候还没注册到容器中)
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}
    ***************************************************************
}

        处理完毕的configClass 对象 会添加到解析器 的 configurationClasses 属性中(这个属性要记得 后续还要统一处理)

现在在回到引导类的处理中

// 
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
    ***************************************************
            // 扫@Component类就是从这进来的还记得吗
            // 那现在scannedBeanDefinitions 就是 MyConfig & TestController两个
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
            this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // 遍历获取到的Bean定义(这些Bean定义都有 @Component注解)
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                // 检查下该Bean定义是否标注了@Configuration注解 如果是 则进行递归调用
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    // 在这里刚刚解析的是MyConfig 加载了@Bean对象
                    // 再次回到这里 解析的则是TestController
                    // 不过没有做什么 执行之后仅是在解析器的 configurationClasses中又添加了一个对象
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
    ***************************************************
}
@Import处理

接下来就要进行引导类中@Import 注解的解析动作了

还是doProcessConfigurationClass这个方法

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
    ***********************上面是刚才看的解析@ComponentScan****************************
    // 解析@Import 注解
    // 这个方法 即重要也不重要 因为它并没有执行Import的逻辑 而是加载了Import类
    // 我们分两个方法来看 
    // 第一个是获取引导类上@Import 的方法getImports
    // 第二个是注册我们获取到的列表 的方法processImports
    processImports(configClass, sourceClass, getImports(sourceClass), true);
    ***************************************************
}

getImports

	private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
		Set<SourceClass> imports = new LinkedHashSet<>();
		Set<SourceClass> visited = new LinkedHashSet<>();
        // 传入的是引导类
		collectImports(sourceClass, imports, visited);
		return imports;
	}

collectImports

	private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
			throws IOException {

		if (visited.add(sourceClass)) {
            // 获取引导类上的注解列表 这里是@SpringBootApplication
			for (SourceClass annotation : sourceClass.getAnnotations()) {
                // 获取注解名
				String annName = annotation.getMetadata().getClassName();
                // 该注解是不是Import 不是则进行递归
				if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
					collectImports(annotation, imports, visited);
				}
			}
            // 到这就说明它标注的注解都遍历过了 如果该类上有Import注解 则将该Import 添加到列表中
			imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
		}
	}

----------------------------------------------------------
/*
 *  这个方法本身其实并不复杂 总而言之就是筛选出引导类上的@Import注解 获取其value属性
 *  那么我们回过头来看下引导类上的注解结构
 *  @SpringBootApplication
         @SpringBootConfiguration
             @Configuration
         @EnableAutoConfiguration
             @AutoConfigurationPackage
                 @Import(AutoConfigurationPackages.Registrar.class)
             @Import(AutoConfigurationImportSelector.class)
         @ComponentScan
    可以看到我们能加载到 AutoConfigurationPackages.Registrar & AutoConfigurationImportSelector 俩个类
    @Import引入的对象 会回调某些方法 列举规则如下表所示
 */

@Import引入类型

回调方法

备注

ImportSelector

selectImports

DeferredImportSelector

selectImports

本身是ImportSelector的子类,但是回调方法的时机与其不同

ImportBeanDefinitionRegistrar

registerBeanDefinitions

其他类型只会实例化导入的类

        那上文中我们知道 加载了 AutoConfigurationPackages.Registrar & AutoConfigurationImportSelector 两个类

其中AutoConfigurationImportSelector 实现了DeferredImportSelector

AutoConfigurationPackages.Registrar 实现了ImportBeanDefinitionRegistrar

// 回到该方法内 我们现在已经拿到了两个 Import类 开始进行赋值
processImports(configClass, sourceClass, getImports(sourceClass), true);

processImports

// 仅看有注释的地方就行
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

		if (importCandidates.isEmpty()) {
			return;
		}

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
				for (SourceClass candidate : importCandidates) {
                    // 判断对象类型 AutoConfigurationImportSelector 能进到这个方法
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
						if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                            // 由于实际类型是DeferredImportSelector 所以将其添加到(当前对象是ConfigurationClassParser 也就是解析器)
                            // this.deferredImportSelectors属性上
							this.deferredImportSelectors.add(
									new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
						}
						else {
                            // 如果不是DeferredImportSelector 类型,就要开始回调方法了 但这里先别看,容易晕
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
                    // 判断对象类型 AutoConfigurationPackages.Registrar 能进到这个方法
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
						ParserStrategyUtils.invokeAwareMethods(
								registrar, this.environment, this.resourceLoader, this.registry);
                        // 这是将对象加载到configClass(引导类)对象的importBeanDefinitionRegistrars属性上
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
				this.importStack.pop();
			}
		}
	}

---------------------------------------------------
/*
    特别注意一下DeferredImportSelector 会注册到解析器 ConfigurationClassParser上
    而ImportBeanDefinitionRegistrar 是注册在configClass上
*/
引导类解析

至此@Import的解析动作就结束了 接下来是要进行回调 回调我们注册的import对象

	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		this.deferredImportSelectors = new LinkedList<>();

		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
                    // 刚刚我们是在这进去进行的解析 启动类解析
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}

        // 现在解析完毕 开始回调(当前this为 解析器ConfigurationClassParser)
		processDeferredImportSelectors();
	}
// 这里贴出了整段代码
// 因为由于各种包装对象 嵌套调用 读起来可能不直观
// 跟着注释慢慢读就好
// 这个方法很重要 其与自动装配有关
private void processDeferredImportSelectors() {
        // 这里拿到的是 AutoConfigurationImportSelector 就是上面我们解析Import的时候赋值的
        // 这里注意下 拿到的是包装类 DeferredImportSelectorHolder 忘了的话先回去看下,确保知道这个对象是怎么来的
		List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
		this.deferredImportSelectors = null;
		if (deferredImports == null) {
			return;
		}

		deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
		Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
		Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();

        // 遍历ImportSelector
		for (DeferredImportSelectorHolder deferredImport : deferredImports) {
            // 这句 获取关系如下
            // deferredImport -> DeferredImportSelectorHolder
            // DeferredImportSelectorHolder.getImportSelector -> AutoConfigurationImportSelector
            // AutoConfigurationImportSelector.getImportGroup -> AutoConfigurationGroup
            // 所以 这里group = AutoConfigurationGroup.class
			Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
            // 这个方法分两部分看
            // 1.createGroup()
                // 这个方法是根据 group类型 生成了一个实例对象 同时复制了环境对象 资源加载器 BeanFactory等对象
                // 也就是所 createGroup() 生成了一个 类型的对象
            // 2.new DeferredImportSelectorGrouping
                // 这就比较好理解 将刚创建的 AutoConfigurationGroup 对象 赋值给 DeferredImportSelectorGrouping的group属性
            // 此时创建的grouping 就是一个包含 AutoConfigurationGroup 的 DeferredImportSelectorGrouping
			DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent(
					(group == null ? deferredImport : group),
					(key) -> new DeferredImportSelectorGrouping(createGroup(group)));
            // 将DeferredImportSelectorHolder 添加到 DeferredImportSelectorGrouping的deferredImports 属性上
			grouping.add(deferredImport);
			configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getConfigurationClass());
		}
		for (DeferredImportSelectorGrouping grouping : groupings.values()) {
            // [重点] DeferredImportSelectorGrouping调用getImports方法
            // 这里就要开始加载自动配置类了,看到这先停下 只看grouping.getImports()
			grouping.getImports().forEach((entry) -> {
				ConfigurationClass configurationClass = configurationClasses.get(
						entry.getMetadata());
				try {
					processImports(configurationClass, asSourceClass(configurationClass),
							asSourceClasses(entry.getImportClassName()), false);
				}
				catch (BeanDefinitionStoreException ex) {
					throw ex;
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to process import candidates for configuration class [" +
									configurationClass.getMetadata().getClassName() + "]", ex);
				}
			});
		}
	}
// 开始看解析方法前 再次明确下对象
// 接下来要看的是DeferredImportSelectorGrouping 的 getImports方法
public Iterable<Group.Entry> getImports() {
    // 还记得刚才赋值的deferredImports吧
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
        // 遍历拿到的deferredImport = DeferredImportSelectorGrouping
        // group也记得吧 group = AutoConfigurationGroup
        // 到这看下面 拓展一:AutoConfigurationGroup.process 方法
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
			deferredImport.getImportSelector());
		}
	return this.group.selectImports();
}

// 拓展一:AutoConfigurationGroup.process 方法
public void process(AnnotationMetadata annotationMetadata,
    	DeferredImportSelector deferredImportSelector) {
    // deferredImportSelector = AutoConfigurationImportSelector
    // 这里准备要加载自动注入的类了
	String[] imports = deferredImportSelector.selectImports(annotationMetadata);
	for (String importClassName : imports) {
		this.entries.put(importClassName, annotationMetadata);
	}
}

deferredImportSelector.selectImports

    // 看自动加载之前我们要知道 这里是AutoConfigurationImportSelector的回调方法
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 这里在获取所有可能的自动配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
        // 移除一些重复的自动配置类
		configurations = removeDuplicates(configurations);
        // 获取需要忽略的类
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        // 检查要排除的类是不是自动配置类
		checkExcludedClasses(configurations, exclusions);
        // 移除忽略的类
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return StringUtils.toStringArray(configurations);
	}
    // 这里在获取所有可能的自动配置类
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
        // 这个方法很熟了吧 之前加载初始化器也是用的这个方法(进去看下就知道了 这里就不重复看了)
        // getSpringFactoriesLoaderFactoryClass 获取出来的是EnableAutoConfiguration.class
        // 这里就是在用自动配置类的key EnableAutoConfiguration 去 Spring.factories 取到所有可能的自动配置类(name)
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
				getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
		Assert.notEmpty(configurations,
				"No auto configuration classes found in META-INF/spring.factories. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

这是我们拿到的自动配置类名如下

回到主体方法中

deferredImportSelector.selectImports

    // 看自动加载之前我们要知道 这里是AutoConfigurationImportSelector的回调方法
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 这里在获取所有可能的自动配置类
        // 这里拿到了109个类名
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
        // 移除一些重复的自动配置类
        // 没有重复的所以还是109个
		configurations = removeDuplicates(configurations);
        // 获取需要忽略的类
        // excludeName & exclude 我们都没设置 所以没有要排除的类
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        // 检查要移除的类是否合法(没有 所以不看)
		checkExcludedClasses(configurations, exclusions);
        // 移除忽略的类
        // 没有要移除的类 还是109
		configurations.removeAll(exclusions);
        // 判断剩下这些类是否满足装配条件
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return StringUtils.toStringArray(configurations);
	}
    // 判断些类是否满足装配条件
    private List<String> filter(List<String> configurations,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		long startTime = System.nanoTime();
        // 将类名List 转为数组
		String[] candidates = StringUtils.toStringArray(configurations);
        // 定义一个跳过数组 用来记录那些类不满足装配条件
		boolean[] skip = new boolean[candidates.length];
		boolean skipped = false;
        // 获取自动装配过滤器
        // getAutoConfigurationImportFilters这个方法也是从spring.factories获取的,感兴趣自行查看
        // 这里只获取到一个过滤器OnClassCondition
		for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
			invokeAwareMethods(filter);
            // 检查那些类不符合装配条件
            // 这个方法 先不关注 只要知道他做了什么
            // 这个方法会检查标注了OnClassCondition注解的类 条件中的类是否已经加载到类加载器中了
            // 如不在 则剔除该自动装配类
			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<>(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");
		}
        // 返回结果集 这里只剩24个类了(省的数量可能不一样 不重要)
		return new ArrayList<>(result);
	}

回到刚开始加载的位置

// 强调下 上面只是在拿可以自动装配的类 还没进行注册呢
// 以上是在AutoConfigurationGroup.process 方法中进行的
public void process(AnnotationMetadata annotationMetadata,
    	DeferredImportSelector deferredImportSelector) {
    // deferredImportSelector = AutoConfigurationImportSelector
    // 这里准备要加载自动注入的类了
	String[] imports = deferredImportSelector.selectImports(annotationMetadata);
	for (String importClassName : imports) {
        // 可以自动装配的类 赋值给entries属性
		this.entries.put(importClassName, annotationMetadata);
	}
}

// 在向上回到 DeferredImportSelectorGrouping 的 getImports方法
public Iterable<Group.Entry> getImports() {
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
        // AutoConfigurationGroup.process从这进的
        // 也就是这一步执行完毕this.group.entries 就有了所有可以自动装配的类的名称了
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
			deferredImport.getImportSelector());
		}
    // 拿到自动配置类的迭代器
	return this.group.selectImports();
}
private void processDeferredImportSelectors() {
       *****************************************************
		for (DeferredImportSelectorGrouping grouping : groupings.values()) {
            // 回到解析器刚刚开始回调DeferredImportSelectors的位置
            // grouping.getImports()拿到了自动配置类名称
			grouping.getImports().forEach((entry) -> {
                // 这里获取下引导类
				ConfigurationClass configurationClass = configurationClasses.get(
						entry.getMetadata());
				try {
                    // 准备注册
					processImports(configurationClass, asSourceClass(configurationClass),
							asSourceClasses(entry.getImportClassName()), false);
				}
				catch (BeanDefinitionStoreException ex) {
					throw ex;
				}
				catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to process import candidates for configuration class [" +
									configurationClass.getMetadata().getClassName() + "]", ex);
				}
			});
		}
	}

        至于processImports方法 其实就是拿着这些自动配置类 再执行一遍 @ComponentScan @Improt之类注解的解析,解析过程和 引导类相同所以就不重复看了,我们只需要知道 这些方法执行完毕之后,生成的自动配置类的configurationClasses 也会添加到解析器中

加载@Bean等对象

        那么至此为止 我们手动注册的Bean 及 自动注入的Bean 都被封装为configurationClasses放在了解析器中了,现在回到最初的解析方法         ConfigurationClassPostProcessor.processConfigBeanDefinitions

// 这里的入参registry 是 BeanFactory
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
***************************************************************
do {
    // 以上那一堆解析代码 都是从这里进来的
    // parse也就是我们所说的解析器
    parser.parse(candidates);
    configClasses.removeAll(alreadyParsed);

	// Read the model and create bean definitions based on its content
	if (this.reader == null) {
		this.reader = new ConfigurationClassBeanDefinitionReader(
				registry, this.sourceExtractor, this.resourceLoader, this.environment,
				this.importBeanNameGenerator, parser.getImportRegistry());
	}
    // 加载所有准备好的configurationClasses
	this.reader.loadBeanDefinitions(configClasses);
   }while (!candidates.isEmpty());
}
private void loadBeanDefinitionsForConfigurationClass(
    ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

    if (trackedConditionEvaluator.shouldSkip(configClass)) {
        String beanName = configClass.getBeanName();
        if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
            this.registry.removeBeanDefinition(beanName);
        }
        this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
        return;
    }

    // 这里其实没什么说法 就是创建Bean定义 注册Bean定义 感兴趣自己追下吧
    // 处理该类被Import注解导入的类
    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }

    // 处理该类被@Bean对象
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

结语

        到这其实Spring Boot的自动配置原理就已经完成了,将自动配置类加载为Bean定义后,实例化Bean对象的过程就和Spring一致了在finishBeanFactoryInitialization(beanFactory)方法里,详情可以去看spring源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值