/**
*这个注解主要是对三个注解的封装
*@SpringBootConfiguration 对@Configuration的派生类,目的就是为了让TestApplication像其他Configuration注解一样。被springboot容器管理,但是为什么要包装呢?其实没有为什么,一个是spring的,一个是springboot的
*@EnableAutoConfiguration spring自动装配,该类主要作用是使用AutoConfigurationImportSelector给容器中导入一些组件,
*然后导出系统中所有spring.factories 文件中是EnableAutoConfiguration的值加入到了容器中,来执行自动装配。主要实现selectImports方法中的getCandidateConfigurations。
*另外,EnableAutoConfiguration 中还实现了@AutoConfigurationPackage注解,查看这个代码,会发现主要是往容器中注入@AutoConfigurationPackage所在类的包路径。
*@ComponentScan 根据定义的扫描路径,把符合扫描规则的类装配到spring容器中
*
* */
@SpringBootApplication
public class IngredientClientApplication {
public static void main(String[] args) {
SpringApplication.run(IngredientClientApplication.class, args);
}
}
spring自动装配主要是执行AutoConfigurationImportSelector类的下面方法实现。如果仔细看,这个类实现DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware接口。仔细观察,会发现这些接口中BeanClassLoaderAware, ResourceLoaderAware,BeanFactoryAware, EnvironmentAware都有一个共同的父类Aware。而官方给的解释是
- Marker superinterface indicating that a bean is eligible to be notified by the Spring container of a particular framework, object through a callback-style method. Actual method signature is determined by individual subinterfaces, but should typically , consist of just one void-returning method that accepts a single argument.
翻译过来的意思就是:标记超接口,指示bean有资格通过回调样式的方法由特定框架对象的Spring容器通知。实际的方法签名由各个子接口决定,但只包含一个接受单个参数的返回void的方法。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//加载"META-INF/"+ "spring-autoconfigure-metadata.properties"文件中的过滤器。
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
//获取注解的属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//这里主要加载的是META-INF/spring.factories文件中名称=org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,这里扫描的是所有的文件
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//使用set去重configurations
configurations = removeDuplicates(configurations);
//返回排除规则。
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//校验并打印不符合自动装配规则的类
checkExcludedClasses(configurations, exclusions);
//移除自动装配的类
configurations.removeAll(exclusions);
//根据过滤规则,过滤
configurations = filter(configurations, autoConfigurationMetadata);
//通知自动配置导入事件,就是通知加载META-INF/spring.factories文件AutoConfigurationImportListener。
fireAutoConfigurationImportEvents(configurations, exclusions);
返回自动装配类
return StringUtils.toStringArray(configurations);
}
@Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties(HttpEncodingProperties.class) //启动指定类的
ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把
HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication //Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class) //判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing =true) //判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
首先执行SpringApplication的构造方法,创建SpringApplication的对象。在创建对象时进行了某些初始参数的设置。
/**
* 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
* @param primarySources the primary bean sources
* @see #run(Class, String[])
* @see #setSources(Set)
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//初始化资源加载器,默认是null。
this.resourceLoader = resourceLoader;
//主资源不能为空,一般主资源就是启动类
Assert.notNull(primarySources, "PrimarySources must not be null");
//初始化主资源,并使用set去重
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//推断应用类型,主要是根据类路径下判断是否包含SpringBootWeb依赖,如果不包含就是NONE类型,包含就是SERVLET类型
this.webApplicationType = deduceWebApplicationType();
//设置应用上下文初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例名称集合并去重,并进行set去重。(一共7个)
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合并去重,并进行set去重。(一共11个)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断主入口应用类,主要是通过new RuntimeException().getStackTrace()获取当前调用栈,获取Main方法所在类,然后赋值给mainApplicationClass
this.mainApplicationClass = deduceMainApplicationClass();
}
上文中主要用到了getSpringFactoriesInstances方法。该方法主要是从从"META-INF/spring.factories"读取传输类的值。处理流程主要有两步,第一步获取"META-INF/spring.factories"中配置的值,第二补,通过反射创建对象。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));//主要查看该方法,该方法中,主要方式是下面loadSpringFactories方法。
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//仔细看这个方法,他其实值执行一次,然后其他时候都在内存中读取。这个方法是获取资源目录下"META-INF/spring.factories"中的配置行,并放到缓存中。并且一次全部获取。
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//获取资源目录下"META-INF/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);
}
}
//通过反射创建对象。
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
接下来,主要介绍springBoot启动运行的run方法。其主要就是初始化信息。代码如下。
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
//创建一个计时器,该计时器依赖于计算机的时间,会有回拨的风险。
StopWatch stopWatch = new StopWatch();
//启动计时器。获取计算机时间的毫秒数,该毫秒数以UTC时间表示
stopWatch.start();
//定义springBoot上下问context
ConfigurableApplicationContext context = null;
//初始化异常报告集合。
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//该方法主要是配置 Spring Boot 应用程序的 headless 属性。headless 属性是一个 boolean 类型的属性,
//用于指定 Spring Boot 应用程序是否在 headless 模式下运行。如果 headless 属性设置为 true,则 Spring Boot 应用程序将在没有显示器的情况下运行
configureHeadlessProperty();
//创建SpringApplicationRunListeners,并从"META-INF/spring.factories"中加载SpringApplicationRunListener的实现类eventPublishingRunListener。
// 注意:这里面有几个特别容易混淆的点。SpringApplicationRunListeners 、SpringApplicationRunListener 、ApplicationListener这三个分别的作用是什么?
//个人理解SpringApplicationRunListener就是一个ApplicationListener的代理,而SpringApplicationRunListeners又是对SpringApplicationRunListener的封装。
//这三个类在启动过程中是联动使用的。另外eventPublishingRunListener又使用SimpleApplicationEventMulticaster实现多播。多播有两种方式,同步和异步。
SpringApplicationRunListeners listeners = getRunListeners(args);
//发布应用启动事件。该启动事件就会执行上述逻辑。通过SpringApplicationRunListeners的starting。
//调用到SpringApplicationRunListener的子类eventPublishingRunListener的starting。
//然后eventPublishingRunListener中借助SimpleApplicationEventMulticaster实现多播到ApplicationListener。
listeners.starting();
try {
//主要用于是处理启动类main函数的参数, 将其封装为一个DefaultApplicationArguments对象, 为prepareEnvironment()提供参数,
//他里面有两个变量,其中 args保存原本的命令行参数, source成员变量保存解析后的命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//根据参数准备环境变量并通知监听器
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//该方法主要是检查系统中有没有设置spring.beaninfo.ignore"属性,如果没有设置,就设置成true,并将"spring.beaninfo.ignore"属性设置为系统属性里面
//设置这个的主要作用是控制Spring框架在创建bean时是否忽略bean的java.beans.BeanInfo接口,而且spring将不再使用BeanInfo创建对象。
configureIgnoreBeanInfo(environment);
//创建banner打印类,这里就是spring启动过程中那个图标
Banner printedBanner = printBanner(environment);
//根据猜测的引用类型,创建应用上下文。就是创建一个容器
context = createApplicationContext();
//准备异常报告器,用来支持报告关于启动的错误
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备应用上下文,将基础信息与应用上下文绑定,就是给容器Context和容器DefaultListableBeanFactory设置属性。具体解释查看prepareContext介绍。
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);
//执行所有的Runner运行器
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;
}
下面这个方法主要是启动类run方法中执行的准备环境变量的方法。该方法主要是将配置文件封装成对象,放在environment中。
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
//创建环境配置类。getOrCreateEnvironment通过获取或者新建两种方式获取配置对象。
ConfigurableEnvironment environment = getOrCreateEnvironment();
//将命令行参数和配置文件中的属性值设置到环境中,这里面调用了两个方法,分别将命令行参数和配置文件中的属性值设置到环境中
configureEnvironment(environment, applicationArguments.getSourceArgs());
//该方法主要是通知SpringApplicationRunListeners中的所有监听器,已经准备好了环境。
//然后监听器主要做了加载application.properties以及application-${active.profile},properties文件。
listeners.environmentPrepared(environment);
//把环境配置绑定到SpringApplication对象上,以便在后续的操作中使用
bindToSpringApplication(environment);
//判断环境类型,如果没有Web服务器,环境会转换为标准环境
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
//这个类其实是将environment环境配置中的source取出重新包装成SpringConfigurationPropertySources。
//并用configurationProperties作为PropertySources。放到sources的第一个。具体为啥放第一。我也不知道。还没研究到那里
ConfigurationPropertySources.attach(environment);
return environment;
}
repareContext介绍。repareContext主要目的是给容器DefaultListableBeanFactory和context设置参数。这个里面有几个点是在做springboot后续扩展时候很关键的点。
看下面类中的信息。listeners.contextPrepared(context)
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//这个主要是给上下文设置前面加载的配置文件信息。主要是提供通过容器能够获取到相关的信息
context.setEnvironment(environment);
//这个主要是设置当前上下文中的resourceLoader和ClassLoader,因为在启动过程中,beanNameGenerator,resourceLoader都是空,所以这里面什么都没做。
postProcessApplicationContext(context);
//这里主要是获取设置到容器中的配置信息(从"META-INF/spring.factories"读取ApplicationContextInitializer类),并执行其中的initialize方法。
//在initialize方法中,主要是给上下文的BeanFactoryPostProcessor和ApplicationLisenter添加值。
//BeanFactoryPostProcessor对容器特有的扩展, 在容器的使用过程中,执行List<BeanFactoryPostProcessor> 对应的方法,进行扩展点的执行。在这里可以对Spring做2次开发。
applyInitializers(context);
//表示 ApplicationContext 准备完成,执行SpringApplicationRunListeners执行contextPrepared方法对上下文可以做一定的处理。
//这里主要执行的是EventPublishingRunListener的contextPrepared方法。但是什么都没做。应该是给以后预留的。
listeners.contextPrepared(context);
//记录上下文处理日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
//将 springApplicationArguments 注册为单例Bean实例
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
//将 springBootBanner注册为单例Bean实例
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources 获得启动时加载参数的资源新
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 这里面主要做了两件事情,1.创建BeanDefinitionLoader类。该类中主要包含Class用AnnotatedBeanDefinitionReader处理、Resource用XmlBeanDefinitionReader处理
//Package用ClassPathBeanDefinitionScanner处理。2.把资源类(这里只有@SpringBootApplication注解修饰的启动类)注册到BeanFactory中
load(context, sources.toArray(new Object[0]));
//下面这个方法主要做了
listeners.contextLoaded(context);
}
/**
* Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
* apply additional processing as required.
* @param context the application context
*/
//beanNameGenerator和resourceLoader默认为空,没有做任何的处理。
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
/**
* Apply any {@link ApplicationContextInitializer}s to the context before it is
* refreshed.
* @param context the configured ApplicationContext (not refreshed yet)
* @see ConfigurableApplicationContext#refresh()
*/
//
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
/**
* Apply any {@link ApplicationContextInitializer}s to the context before it is
* refreshed.
* @param context the configured ApplicationContext (not refreshed yet)
* @see ConfigurableApplicationContext#refresh()
*/
//主要目的是初始化容器,并把
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
public void contextLoaded(ConfigurableApplicationContext context) {
// 获取SpringApplication实例化的时候创建的10个监听器
for (ApplicationListener<?> listener : this.application.getListeners()) {
// 如果该监听器是ApplicationContextAware的实例,则把ApplicationContext设置到监听器中
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
// 把SpringApplication实例化的时候创建的10个监听器Listener注册到ApplicationContext容器中。
context.addApplicationListener(listener);
}
// 广播出ApplicationPreparedEvent事件给相应的监听器执行
this.initialMulticaster.multicastEvent(
new ApplicationPreparedEvent(this.application, this.args, context));
}
refreshContext(context);
refreshContext(context);
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
/
//这个方法在AbstractApplicationContext中。是Spring中加载Bean的核心方法,主要进行类的自动装配、注册、解析、注入
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//刷新上下文环境,初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验,这里面主要包含三个方法
//1.initPropertySources() 这里面什么都没做,源码备注需要子类实现。这个方法主要实现上下文中占位符的替换。
//2.getEnvironment().validateRequiredProperties();这里面主要是校验所有需要的属性
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//该实现对上下文的底层bean工厂执行实际刷新,,并为上下文生命周期的下一阶段初始化一个建一个新的DefaultListableBeanFactory对象工厂。
//这里系统提供了两种实现方式,一种是删除后新建,一种是取出上下文中的beanFactory并返回。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//待后续继续研究
// Prepare the bean factory for use in this context.
//对beanFactory的各种功能进行填充,包括设置ClassLoader、添加PostProcessor,设置编辑注册器,添加applicationContextAwareprocessor处理器等
//扩展点:这里面applicationContextAwareprocessor的作用是啥呢。这个类用于在Bean实例化过程中进行定制化的处理。再bean实例化前。
//会执行applicationContextAwareprocessor#postProcessBeforeInitialization(),在这个方法中,ApplicationContextAwareProcessor会检测当前处理的Bean是否实现了
//ApplicationContextAware接口,这样Bean就可以通过调用getApplicationContext方法来获取到Spring应用上下文的引用。
//再日常使用中,大家经常创建一个SpringContextUtils implements ApplicationContextAware就是这个类做的
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//提前处理BeanFactory中的后置处理器。在这一步中,可以对BeanFactory进行自定义的处理,例如添加自定义的后置处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//激活各种beanfactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//分类、排序、注册(注入)所有的BeanPostProcessors,用于处理 bean 的初始化流程
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化上下文中的资源文件如国际化文件和多语言的处理
initMessageSource();
// Initialize event multicaster for this context.
//初始化上下文事件广播器,也就是注册 applicationEventMulticaster SingletonBean
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//给子类扩展初始化其他bean
onRefresh();
// Check for listener beans and register them.
//注册监听着
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//初始化剩余的非懒惰的bean,即初始化非延迟加载的bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//发完成刷新过程,通知声明周期处理器刷新过程,同时发出ContextRefreshEvent通知别人
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();
}
}
}
//PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())解析
//该方法的主要功能就是执行BeanFactoryPostProcessors。
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<>();
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<>();
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();
}