Spring Boot-6-启动流程

Spring Boot的启动过程涉及甚广,要将Spring Boot的启动流程吃透,需要将Spring的所有功能都理解到位,因为启动的过程是为后续各个功能服务的。

Spring Boot的主要功能是IoC容器,所以主要功能是扫描Bean,然后实例化Bean,在阅读整个源码的时候,一定要不停的追问这个和IoC容器有什么关系?

Spring Boot的IoC容器有2个重要类体系,一个BeanFactory,另一个是ApplicationContext,且ApplicationContext聚合了BeanFactory,且ApplicationContext实现了BeanFactory的接口,所以ApplicationContext是具备了BeanFactory的类型和能力的。

ApplicationContext是有许多成员变量的,BeanFactory也是有很多成员变量的,最重要的是beanDefinitionMap,这个是扫描到的Bean的定义,实例化Bean时得靠他。另外我们知道,Spring Boot中有singleton类型的Bean的,这类Bean是创建一次后就需要缓存的,存储的结构是:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects = private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);其他非singleton的Bean就是需要实时的实例化,不需要对象结构来存储。
真正的依赖注入是发生在org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean()这个方法上的。

Spring Boot的内置了Tomcat,启动入口要比外置Tomcat要更容易寻找到和理解。
一个简单的Spring Boot应用的入口如下:
SpringApplication提供了一个public static 的run方法,primarySource参数是单个对象,这些都是方便外部调用。

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

一、SpringApplication静态run()方法

来看下实现,这里自定义的启动类被称为primarySource,它的含义是启动源头,这个类上面会有注解,是Spring Boot启动的源头,所以才叫source。

/**
 * Static helper that can be used to run a {@link SpringApplication} from the
 * specified source using default settings.
 * @param primarySource the primary source to load
 * @param args the application arguments (usually passed from a Java main method)
 * @return the running {@link ApplicationContext}
 */
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
}

run()方法对内是有重载的,这是一个基本的技巧,对外的方法应该是简单易用,对内的方法是扩展性强,所以重载的run()方法接收数组参数,扩展性好,但是使用起来不便,所以对外提供了单个对现象的参数,方便使用。

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

二、SpringApplication构造方法

primarySource传递给了SpringApplication的构造方法,args给了一个非静态的run()方法。下面我们先来看看SpringApplication的构造方法。这里的文档解释了一点关于primaySource的信息,创建一个新的SpringApplication实例,application context将会从指定的primary source加载beans,新的SpringApplication实例在被调用前能够被定制。primarySources:基础bean源。

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * {@link #run(String...)}.
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #SpringApplication(ResourceLoader, Class...)
 * @see #setSources(Set)
 */
public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
}

创建一个SpringApplication实例,application context将会从指定的primary sources上加载beans。这个SpringApplication实例能在调用run方法前被定制。
SpringApplication构造方法里做的都是一些成员变量初始化的工作,虽然只是初始化工作,但要看初始化的是谁,这里初始化了org.springframework.context.ApplicationContextInitializer和org.springframework.context.ApplicationListener,这2个接口对应的实例都会在后面启动流程中被调用,所以这2个操作
setInitializers()
setListeners()
是一个惰性操作,这里只是设置了监听器等,到后面的某个时机才会被调用。而且通常是关键的启动步骤。
这两个方法里的获取的ApplicationContextInitializer和ApplicationListener是从META-INF/spring.factories中得到的。

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * {@link #run(String...)}.
 * @param resourceLoader the resource loader to use,这里是null
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #setSources(Set)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
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 = WebApplicationType.deduceFromClasspath();
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

我们先来看下setInitializers()这个方法,泛型方法,使用了通配符,并且限定类型上界。

public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
	this.initializers = new ArrayList<>(initializers);
}
/**
 * 一个泛型方法,参数是ApplicationContextInitializer.class
 */
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
	return getSpringFactoriesInstances(type, new Class<?>[] {});
}

注意这里需要ClassLoader,你应该知道为什么需要ClassLoader。这里只传递了第一个参数,其他的都是没有实际值的。getClassLoader()方法可以自行去研究,这里先不做说明。

这里主要是SpringFactoriesLoader#loadFactoryNames(...)方法,内部调用的是SpringFactoriesLoader#loadSpringFactories(...),这个方法会返回一个Map<String,List<String>>,key是某个类型的全类名,List的值也是某个类型的全类名,且一般都是key的子类型,这些类型都是从classpath下的META-INF/spring.factories目录下遍历得到的,也就是说会去遍历所有jar包的META-INF/spring.factories文件,然后loadFactoryNames(...)方法是从Map里getOrDefault()了一个元素。取到了一个全类名的List<String>列表后,通过反射实例化这些类型,然后排序后返回,总的来说,SpringApplication#getSpringFactoriesInstances(...)方法就是从所有jar包中读取指定类型并实例化返回排序后的对象。下面的setListeners(...)方法和上面setInitializers(...)如出一辙。下面的deduceMainApplicationClass()方法就是通过检查哪个类有main方法,然后确定这个类为启动类。

    至此,我们分析了SpringApplication()的构造方法,总的来说,里面的逻辑全部都是给SpringApplication类里的Field赋值而已。

SpringApplication#getSpringFactoriesInstances(...)

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
	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<?> factoryType, @Nullable ClassLoader classLoader) {
	String factoryTypeName = factoryType.getName();
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

 三、SpringApplication非静态run()方法

下面我们来看下SpringApplication#run(...)方法,这个run()方法是非静态的方法,也就是实例方法,可以肯定的是,这个方法运行结束后,Spring Boot应用就启动完成了,所以这短短的一段代码显然是有很多内容的。

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		refreshContext(context);
		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、先看StopWatch,stop watch的意思是秒表,这里用来给SpringApplication启动计实的,很简单独立的功能,可以自行看源码。

2、configureHeadlessProperty()方法就是调用了System.setProperty()设置了key为java.awt.headless的属性值,具体有什么作用还没有研究。

3、SpringApplication#getRunListeners(...),这个方法返回的是SpringApplicationRunListeners实例,这个类型就是SpringApplicationRunListener的一个list,方法就是遍历调用list里SpringApplicationRunListener方法,很简单的逻辑。

private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
	return new SpringApplicationRunListeners(logger,
			getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

SpringApplication#getSpringFactoriesInstances()是我们熟悉的方法,上面已经介绍过了,他是去找所有jar包中META-INF/spring.factories文件中配置的指定的SpringApplicationRunListener类型的子类型,返回其实例们。可以看到这个listeners是在SpringApplication启动的关键节点手动调用一下其中的方法,逻辑很好理解。

4、SpringApplication#prepareEnvironment(...)
下面的getOrCreateEnvironment()方法没有什么复杂的逻辑,就是根据当前application类型简单实例化不同environment而已。这里通常是StandardServletEnvironment这个类型。接下来configureEnvironment(...)作用不详。ConfigurationPropertySource.attach(...)方法是个静态方法,作用是将一个或多个property文件挂到到environment上面去,这里可以看到不同作者对函数的命名是有个人特点的,不过都是好理解的。下面listeners.environmentPrepared(...)就是回调监听器的对应方法告知监听者。接下来bindToSpringApplication(...)作用不详。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

5、SpringApplication#configureIgnoreBeanInfo(...)

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
	if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
		Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
		System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
	}
}

这个方法从environment中读取名字为spring.beaninfo.ignore的属性值,然后设置到System中,逻辑简单,可自行查阅源码。

6、SpringApplication#createApplicationContext()

这个方法比较简单,就是根据当前application环境来实例化不同applicationContext。但是applicationContext是包含了整个应用的信息的,他是Spring应用所有东西的大箱子,你需要的东西基本上都要从他这里拿。
这里会给applicationContext里的成员变量赋值,有一些变量是我们很关心的。

protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				contextClass = Class.forName(DEFAULT_SERVLET_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);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

7、exceptionReporters赋值

这个变量的赋值调用的又是我们熟悉的getSpringFactoriesInstances(...),他是去找所有jar包中META-INF/spring.factories文件中配置的指定的SpringApplicationRunListener类型的子类型,返回其实例们。

8、SpringApplication#prepareContext()
prepareContext(...)方法有个很实在的功能就是给conext里的成员变量赋值,比如给
org.springframework.context.support.AbstractApplicationContext#beanFactoryPostProcessors  = private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors 的赋值,但不是全部,只给了3个,后面流程还会继续添加,
注意,这个context里的成员变量不是IoC容器里的,IoC容器里有BeanFactoryPostProcessor,而且IoC里的BeanFactoryPostProcessor才是处理扫描Bean的。
他还干了个重要的事情,调用监听器,监听器做的事情也很多。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
		SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	applyInitializers(context);
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}

10、SpringApplication#refreshContext(context);
这个方法是个工作量巨大的方法,也是众多关键点涉及的地方,包括我们最关心的bean的装载。
SpringApplication#createApplicationContext()、SpringApplication#prepareContext()、SpringApplication#refreshContext(),这三个方法是BeanDefinition注册的三个地方,这一点我们之前提到过,注意这里注册的bean不仅仅是业务逻辑自定义的额bean,还有很多spring框架里的bean,并且前面2个方法扫描的BeanDefinition只有6个,且基本都是spring的只有一个自定义的启动类,后面的refreshContext()方法才是真正扫面BeanDefinition的主力,存储BeanDefinition的结构是org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionMap = private final Map<String, BeanDefinition> beanDefinitionMap,

SpringApplication#refreshContext(context)最终调用的是org.springframework.context.support.AbstractApplicationContext#refresh()
里面有个invokeBeanFactoryPostProcessors(beanFactory),且我们知道BeanFactoryPostProcessor是在SpringApplication#prepareContext()中计算出来的。
在执行完invokeBeanFactoryPostProcessors()方法后,beanDefinitionMap就满了,所以扫描BeanDefinition的任务就是在这个方法里完成的,

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			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();
		}
	}
}

我们要好好看看AbstractApplicationContext#invokeBeanFactoryPostProcessors()
不用怀疑,就是上面这个PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()是主要逻辑所在,这里用到了委托机制,委托机制仅仅是个很简单的调用而已,不是什么模式,因为他太简单,只是帮助我们解决了命名问题而已。
我们发现有三个BeanFactoryPostProcessor(3个都是在SpringApplication#prepareContext()方法里完成赋值):
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer$ConfigurationWarningsPostProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor
org.springframework.boot.context.config.ConfigFileApplicationListener$PropertySourceOrderingPostProcessor implements BeanFactoryPostProcessor, Ordered

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}
}

下面是委托类的代码:
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanFactoryPostProcessor>) 
我们看到有个判断context是BeanDefinitionRegistry的实例的逻辑,我们使用的org.springframework.beans.factory.support.DefaultListableBeanFactory就实现了BeanDefinitionRegistry接口
然后将BeanFactoryPostProcessor划分为2类,一类是常规类型regularPostProcessors,一类是注册功能类型registryProcessors,判断的依据是是否是是org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor类型
注意在分类是顺便将BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()方法执行了,regular类型没有执行,因为注册的事情必须要先做,但是这3个执行完了beanDefinitionMap也没有增加什么,真是白忙活了这么久,
主要靠下面 beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false)
这个又重新查出来一个ConfigurationClassPostProcessor,因为上面的BeanFactoryPostProcessor是context的成员变量,他是Spring框架写死的,不方便扩展,而这个ConfigurationClassPostProcessor是注册到容器里的,这种方式就比较容易扩展,
且需要注意的是,容器是在BeanFactory里面的,context是聚合了BeanFactory,ConfigurationClassPostProcessor这个确实是真正干活的
看到下面这个方法,你会看到一遍一遍的执行BeanPostProcess,为什么呢?因为在调用一个BeanPostProcess的时候,他会扫描进另外的一些框架定义的BeanPostProcess,所以会出现多次执行,像是重复代码一样。
下面while(reiterate)就是这个意思,reiterate的意思就是重复说,重复迭代的意思。

public static void invokeBeanFactoryPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
	Set<String> processedBeans = new HashSet<>();

	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				registryProcessors.add(registryProcessor);
			}
			else {
				regularPostProcessors.add(postProcessor);
			}
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		// Separate between BeanDefinitionRegistryPostProcessors that implement
		// PriorityOrdered, Ordered, and the rest.
		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

		// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();

		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
		postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
		currentRegistryProcessors.clear();

		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
		boolean reiterate = true;
		while (reiterate) {
			reiterate = false;
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
					reiterate = true;
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();
		}

		// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	}

	else {
		// Invoke factory processors registered with the context instance.
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}

	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let the bean factory post-processors apply to them!
	String[] postProcessorNames =
			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

	// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (processedBeans.contains(ppName)) {
			// skip - already processed in first phase above
		}
		else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
		}
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String postProcessorName : orderedPostProcessorNames) {
		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

	// Finally, invoke all other BeanFactoryPostProcessors.
	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String postProcessorName : nonOrderedPostProcessorNames) {
		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

	// Clear cached merged bean definitions since the post-processors might have
	// modified the original metadata, e.g. replacing placeholders in values...
	beanFactory.clearMetadataCache();
}

可以很明确的指出org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法就是扫描BeanDefinition的主要逻辑:

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
	int registryId = System.identityHashCode(registry);
	if (this.registriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
	}
	if (this.factoriesPostProcessed.contains(registryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + registry);
	}
	this.registriesPostProcessed.add(registryId);

	processConfigBeanDefinitions(registry);
}

接下来干活的是:org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions()
这个方法是扫描的具体逻辑了,看起来就够复杂了,这里有个candidateNames变量,我更愿意称他为种子变量,因为他是Bean扫描的源头,他是从BeanFactory中获取来的,一般而言会有7、8个左右,
BeanDefinition beanDef = registry.getBeanDefinition(beanName); // 这里会有7到8个左右,包括我们的启动类

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();

	for (String beanName : candidateNames) {
		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
			}
		}
		else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
			configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
		}
	}

        // 遍历后发现只有我们的启动类入围,其他的都被过滤了
	// Return immediately if no @Configuration classes were found
	if (configCandidates.isEmpty()) {
		return;
	}

        // 排个序
	// Sort by previously determined @Order value, if applicable
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});

	// Detect any custom bean name generation strategy supplied through the enclosing application context
	SingletonBeanRegistry sbr = null;
        // 这里判断为true,因为DefaultListableBeanFactory的父接口ConfigurableListableBeanFactory有这个基因
	if (registry instanceof SingletonBeanRegistry) {
		sbr = (SingletonBeanRegistry) registry;
		if (!this.localBeanNameGeneratorSet) {
			BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
			if (generator != null) {
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}
	}

	if (this.environment == null) {
		this.environment = new StandardEnvironment();
	}

	// Parse each @Configuration class
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);

	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
                // 这里最开始只有一个启动类作为入参,执行完这句就解析了对应的bean
		parser.parse(candidates);
		parser.validate();

		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
		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());
		}
		this.reader.loadBeanDefinitions(configClasses);
		alreadyParsed.addAll(configClasses);

		candidates.clear();
		if (registry.getBeanDefinitionCount() > candidateNames.length) {
			String[] newCandidateNames = registry.getBeanDefinitionNames();
			Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
			Set<String> alreadyParsedClasses = new HashSet<>();
			for (ConfigurationClass configurationClass : alreadyParsed) {
				alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
			}
			for (String candidateName : newCandidateNames) {
				if (!oldCandidateNames.contains(candidateName)) {
					BeanDefinition bd = registry.getBeanDefinition(candidateName);
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
							!alreadyParsedClasses.contains(bd.getBeanClassName())) {
						candidates.add(new BeanDefinitionHolder(bd, candidateName));
					}
				}
			}
			candidateNames = newCandidateNames;
		}
	}
	while (!candidates.isEmpty());

	// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
	if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
		sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
	}

	if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
		// Clear cache in externally provided MetadataReaderFactory; this is a no-op
		// for a shared cache since it'll be cleared by the ApplicationContext.
		((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
	}
}


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值