After analyzing the loading of BeanFactory containers, let's take a look at the loading of ApplicationContext, a more complex container that we currently use. Compared with BeanFactory, ApplicationContext has the following differences:
1. Inherit MessageSource and provide international standard access policy.
2. Inherit ApplicationEventPublisher and provide powerful event mechanism.
3. Expand ResourceLoader, which can be used to load multiple resources and flexibly access different resources.
4. Support for Web applications.
You can also start with a line of code:
ApplicationContext bs = new ClassPathXmlApplicationContext("beanFactoryTest.xml");
Look at the UML diagram of Applicationcontext:
And ClassPathXmlApplicationContext
First, the constructor of ClassPathXmlApplicationContext:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { //Support multiple profiles passed in in array mode at the same time this(new String[] {configLocation}, true, null); } public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { //(1) Set parent class super(parent); //(2) Set profile address setConfigLocations(configLocations); //(3) Refresh if (refresh) { refresh(); } }
(1)super(parent); the implementation is in AbstractApplicationContext with the attribute private ApplicationContext parent;
(2)setConfigLocations(configLocations); the implementation is in abstractrefreshableconfiguapplicationcontext:
public void setConfigLocations(@Nullable String... locations) { if (locations != null) { Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; //Set the parameters one by one into the member variable private String[] configLocations; for (int i = 0; i < locations.length; i++) { //If there are special characters such as ${var}, resolvePath searches for matching system variables and replaces them this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } }
(3) refresh() is implemented in AbstractApplicationContext
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //Context environment ready to refresh prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //Initialize BeanFactory and read XML file ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //Fill in various functions of beanFactory prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //Subclass override method for additional processing postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //Activate various BeanFactory processors invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //Register Bean processor registerBeanPostProcessors(beanFactory); // Initialize message source for this context. //Initialize Message source initMessageSource(); // Initialize event multicaster for this context. //Initialize application message broadcaster initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. //Leave subclasses to initialize other beans onRefresh(); // Check for listener beans and register them. //Register listener registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //Initialize the remaining singletons (non lazy) finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //Complete the refresh process 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(); } } }
A lot of things have been done in the process of refreshing. The following methods are analyzed one by one:
1. Environment preparation prepareRefresh();
protected void prepareRefresh() { //start time this.startupDate = System.currentTimeMillis(); //Not closed this.closed.set(false); //Active state this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment //Empty implementation, leaving subclass coverage initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties //Necessary validation of attributes getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); }
2. Load BeanFactory and implement it in AbstractApplicationContext
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //Initialize BeanFactory and read information from xml refreshBeanFactory(); //Get BeanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
refreshBeanFactory, which is implemented in AbstractRefreshableApplicationContext
@Override protected final void refreshBeanFactory() throws BeansException { //If BeanFactory already exists, destroy beans and close BeanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //Create DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); //Serialize the specified id beanFactory.setSerializationId(getId()); //Custom BeanFactory customizeBeanFactory(beanFactory); //Initialize DocumentReader to read and parse XML file loadBeanDefinitions(beanFactory); //Bind member variable synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
//Destroy all instantiated bean s protected void destroyBeans() { getBeanFactory().destroySingletons(); } @Override public void destroySingletons() { super.destroySingletons(); //1. Delete the manualSingletonNames in DefaultListableBeanFactory this.manualSingletonNames.clear(); //Delete allBeanNamesByType and singletonBeanNamesByType clearByTypeCache(); } @Override public void destroySingletons() { super.destroySingletons(); //Delete factoryBeanObjectCache from FactoryBeanRegistrySupport this.factoryBeanObjectCache.clear(); } //Finally, clear the map in DefaultSingletonBeanRegistry public void destroySingletons() { if (logger.isDebugEnabled()) { logger.debug("Destroying singletons in " + this); } synchronized (this.singletonObjects) { this.singletonsCurrentlyInDestruction = true; } String[] disposableBeanNames; synchronized (this.disposableBeans) { disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); } for (int i = disposableBeanNames.length - 1; i >= 0; i--) { destroySingleton(disposableBeanNames[i]); } this.containedBeanMap.clear(); this.dependentBeanMap.clear(); this.dependenciesForBeanMap.clear(); synchronized (this.singletonObjects) { this.singletonObjects.clear(); this.singletonFactories.clear(); this.earlySingletonObjects.clear(); this.registeredSingletons.clear(); this.singletonsCurrentlyInDestruction = false; } }
@Override //If there is a bound beanFactory in AbstractRefreshableApplicationContext, the binding is unbound. protected final void closeBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory != null) { this.beanFactory.setSerializationId(null); this.beanFactory = null; } } }
Create BeanFactory
protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
Specify the id, and assign the id of applicationContext to the serializationId of BeanFactory
public void setSerializationId(@Nullable String serializationId) { if (serializationId != null) { serializableFactories.put(serializationId, new WeakReference<>(this)); } else if (this.serializationId != null) { serializableFactories.remove(this.serializationId); } this.serializationId = serializationId; }
Customized BeanFactory, added whether to allow coverage or extension
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
Load BeanDefinition and implement it in AbstractXmlApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory.'' //Create XmlBeanDefinitionReader for the specified BeanFactory XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. //Setting environment variables beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. //Set up initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //Get xml resources Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } //Get xml address String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
3. Function expansion
Next, enter prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. //Set classLoader of beanFactory to classLoader of current context beanFactory.setBeanClassLoader(getClassLoader()); //Add SPEL resolver. This is to call applyPropertyValues of AbstractAutowireCapableBeanFactory class to complete the function. It uses evaluation of beanExpressionResolver beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //Add property editor beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. //Add ApplicationContextAwareProcessor beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //Ignore several auto assembly interfaces beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. //Set special rules for automatic assembly beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. //Add post processor to detect internal beans beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. // Add support for AspectJ if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. //Add default system variable bean if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
Add attribute registration editor
The root cause of this step goes back to the initBeanWrapper method. At this time, the registerCustomEditors of the resourceeditorregister will be called.
protected void initBeanWrapper(BeanWrapper bw) { bw.setConversionService(getConversionService()); registerCustomEditors(bw); }
//beanWrapper inherits PropertyEditorRegistry, so it is also a registry protected void registerCustomEditors(PropertyEditorRegistry registry) { PropertyEditorRegistrySupport registrySupport = (registry instanceof PropertyEditorRegistrySupport ? (PropertyEditorRegistrySupport) registry : null); if (registrySupport != null) { registrySupport.useConfigValueEditors(); } if (!this.propertyEditorRegistrars.isEmpty()) { //Traverse the PropertyEditorRegistrar in the propertyEditorRegistrars registered in AbstractBeanFactory, and call one by one registrar.registerCustomEditors(registry) method for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) { try { registrar.registerCustomEditors(registry); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; String bceBeanName = bce.getBeanName(); if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) { if (logger.isDebugEnabled()) { logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() + "] failed because it tried to obtain currently created bean '" + ex.getBeanName() + "': " + ex.getMessage()); } onSuppressedException(ex); continue; } } throw ex; } } } if (!this.customEditors.isEmpty()) { this.customEditors.forEach((requiredType, editorClass) -> registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass))); } }
Next, we need to know where the propertyeditorregistratiors in AbstractBeanFactory come from. In fact, it is the line of code we are most concerned about:
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
@Override public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) { Assert.notNull(registrar, "PropertyEditorRegistrar must not be null"); //Added ResourceEditorRegistrar to propertyEditorRegistrars this.propertyEditorRegistrars.add(registrar); }
registerCustomEditors of ResourceEditorRegistrar called
@Override public void registerCustomEditors(PropertyEditorRegistry registry) { ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver); doRegisterEditor(registry, Resource.class, baseEditor); doRegisterEditor(registry, ContextResource.class, baseEditor); doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor)); doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor)); doRegisterEditor(registry, File.class, new FileEditor(baseEditor)); doRegisterEditor(registry, Path.class, new PathEditor(baseEditor)); doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor)); doRegisterEditor(registry, URL.class, new URLEditor(baseEditor)); ClassLoader classLoader = this.resourceLoader.getClassLoader(); doRegisterEditor(registry, URI.class, new URIEditor(classLoader)); doRegisterEditor(registry, Class.class, new ClassEditor(classLoader)); doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader)); if (this.resourceLoader instanceof ResourcePatternResolver) { doRegisterEditor(registry, Resource[].class, new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver)); } }
Call doRegisterEditor one by one
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) { if (registry instanceof PropertyEditorRegistrySupport) { ((PropertyEditorRegistrySupport) registry).overrideDefaultEditor(requiredType, editor); } else { registry.registerCustomEditor(requiredType, editor); } }
@Override public void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor) { registerCustomEditor(requiredType, null, propertyEditor); }
@Override public void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor) { if (requiredType == null && propertyPath == null) { throw new IllegalArgumentException("Either requiredType or propertyPath is required"); } if (propertyPath != null) { if (this.customEditorsForPath == null) { this.customEditorsForPath = new LinkedHashMap<>(16); } this.customEditorsForPath.put(propertyPath, new CustomEditorHolder(propertyEditor, requiredType)); } else { if (this.customEditors == null) { this.customEditors = new LinkedHashMap<>(16); } //The last trace is to put this type and corresponding resolver into the map of customEditors in PropertyEditorRegistrySupport this.customEditors.put(requiredType, propertyEditor); this.customEditorCache = null; } }
ok, the Attribute Editor has finished parsing. When the input value needs to be parsed, the corresponding parser will be found.
The next step is beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
I'm familiar with the post processor. I'm mainly familiar with the ApplicationContextAwareProcessor. The post-processing is not implemented. Take a look at the pre-processing:
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { AccessControlContext acc = null; if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) { acc = this.applicationContext.getBeanFactory().getAccessControlContext(); } if (acc != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareInterfaces(bean); return null; }, acc); } else { invokeAwareInterfaces(bean); } return bean; }
//spring provides corresponding injection after initialization for bean s that implement the following interfaces private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }
So the next step is to ignore the corresponding interface. After that, it is also necessary to have the function since registration.
4. Activate various BeanFactory processors. Note that it is activated.
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())); } }
There are two types of BeanFactoryPostProcessor, BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor, BeanDefinitionRegistryPostProcessor extensions BeanFactoryPostProcessor. The calling order is that BeanDefinitionRegistryPostProcessor takes precedence over BeanFactoryPostProcessor and BeanFactoryPostProcessor takes precedence over bean instantiation.
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<>(); //Processing of BeanDefinitionRegistry type if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; //Create two list s, regular postprocessor and registration processor List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>(); //Traverse factory postprocessor for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; //Call the postProcessBeanDefinitionRegistry method and add it to the list registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { //Add directly to the corresponding list without calling the method 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. // BeanDefinitionRegistryPostProcessor used to save the current processing List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. // First, we deal with the BeanDefinitionRegistryPostProcessor that implements the PriorityOrdered (limited sorting interface) 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); } } // sort sortPostProcessors(currentRegistryProcessors, beanFactory); // Join the registryProcessors collection registryProcessors.addAll(currentRegistryProcessors); // Call postProcessBeanDefinitionRegistry() of all BeanDefinitionRegistryPostProcessors that implement PriorityOrdered invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // Empty for next use currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. // Second, the call is BeanDefinitionRegistryPostProcessors that implements 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. // Finally, call the other BeanDefinitionRegistryPostProcessors. 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. // If it is not BeanDefinitionRegistry, just call its callback function (postProcessBeanFactory()) 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. // We also need to distinguish PriorityOrdered, Ordered and no Ordered 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(); }