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();
}
}