The target
Trace the flow of the following code:
AnnotationConfigApplicationContextDemo
/**
* @description
* @date 2021-06-30 11:21
**/
public class AnnotationConfigApplicationContextDemo {
public static void main(String[] args) {
final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SimpleConfig.class);
User user = applicationContext.getBean(User.class);
System.out.println("user:" + user);
}
}
Copy the code
@Configuration public class SimpleConfig { @Bean public User user(){ return new User("xgimi", 10); }}Copy the code
public class User { private String name; private Integer age; .Copy the code
process
The core logic are AnnotationConfigApplicationContext take participate in the constructor:
public AnnotationConfigApplicationContext(Class<? >... componentClasses) { this(); register(componentClasses); refresh(); }Copy the code
What does the empty constructor do
BedefinitionReader BeanDefinitionScanner BeanDefinitionScanner BeanDefinitionScanner BeanDefinition 2 it is through the constructor of the superclass GenericApplicationContext created DefaultListableBeanFactory, provide the underlying ability of the IOC.
Initialize AnnotatedBeanDefinitionReader
Public AnnotatedBeanDefinitionReader (BeanDefinitionRegistry registry) {/ / into the registry, Initialize the Environment object this(Registry, getOrCreateEnvironment(Registry)); }Copy the code
Provides the ability to register BeanDefinitions
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
Copy the code
We will explore the nature of BeanDefinitionRegistry registration of Beandefinitions later
GetOrCreateEnvironment this method creates an environment and gets it: getOrCreateEnvironment
private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry instanceof EnvironmentCapable) {
return ((EnvironmentCapable) registry).getEnvironment();
}
return new StandardEnvironment();
}
Copy the code
Environment objects contain system environment variables, custom attributes and other content.
Through the constructor as you can see, AnnotatedBeanDefinitionReader underlying maintains a BeanDefinitionRegistry. In fact, he is to provide the ability of registration by BeanDefinitionRegistry AnnotationConfigApplicationContext itself is a BeanDefinitionRegistry; So the call AnnotatedBeanDefinitionReader constructor, we incoming is AnnotationConfigApplicationContext:
Initialize AnnotatedBeanDefinitionReader
Initialize DefaultListableBeanFactory
The relationship between the first explores the following AnnotationConfigApplicationContext and DefaultListableBeanFactory:
Is actually the combination relationship, the ability of most of AnnotationConfigApplicationContext, including registered beanDefinition, rely on search, dependency injection, is through DefaultListableBeanFactory through the bottom of the ability to support.
How do I register a configuration class as a BeanDefinition
In AnnotationConfigApplicationContext:
@Override public void register(Class<? >... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register") .tag("classes", () -> Arrays.toString(componentClasses)); // Register the configuration class this.reader.register(componentClasses); registerComponentClass.end(); }Copy the code
Reader register (); reader register ()
public void register(Class<? >... componentClasses) { for (Class<? > componentClass : componentClasses) { registerBean(componentClass); }}Copy the code
public void registerBean(Class<? > beanClass) { doRegisterBean(beanClass, null, null, null, null); }Copy the code
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @nullable BeanDefinitionCustomizer[] customizers) {// Convert class objects into beandefinitions, The only class in this BeanDefinition information and commentary on the class notes AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); / / @ Conditional annotate the if (this. ConditionEvaluator. ShouldSkip (abd) for getMetadata ())) {return; } // Supplier takes precedence over all constructor and factory methods for class instantiation, but does not affect property Settings abd.setInstancesupplier (supplier); // Handle scope, no setting, default return singleton; @scope ("scopeName") will do that in this method, Get scopeName ScopeMetadata ScopeMetadata = this. ScopeMetadataResolver. ResolveScopeMetadata (abd); abd.setScope(scopeMetadata.getScopeName()); / / create beanName AnnotationBeanNameGenerator provide capacity, but gives priority to the String to interface into the ginseng beanName = (the name! = null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // Set the values of the following annotations to abD //1.@Lazy 2.@Primary 3.@Role 4.@DependesOn 2.@Primary AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers ! = null) { for (Class<? extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers ! = null) { for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); }} //definitionHolder holds beanDefinition or beanName. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); // If @scope sets the proxy, It will return a proxy object definitionHolder = AnnotationConfigUtils. ApplyScopedProxyMode (scopeMetadata definitionHolder, this.registry); / / will definitionHolder beanDefinition registered to the registry of object / / DefaultListableBeanFactory registerBeanDefinition (String beanName, BeanDefinition BeanDefinition) A beanDefinition DefaultListableBeanFactory beanDefinitionMap in in, To deposit beanDefinitionNames beanName BeanDefinitionReaderUtils. RegisterBeanDefinition (definitionHolder, enclosing registry); }Copy the code
Put the above code together to sort out the general logic of the following doRegisterBean:
- Creates an AnnotationBeanDefinition of the configuration class object
- AnnotationBeanDefinition is used to parse whether there is an @Conditional annotation on the class and determine whether the conditions for registration are met. If not, registration will not be carried out
- Registers the Supplier passed to the method entry in ABD, and the bean is subsequently instantiated through this interface
- Parse the @Scope property and register it with abD
- Create beanName
- Parse the following annotations and register the corresponding properties with ABD
- @Lazy
- @Primary
- @Role
- @DependesOn
- @Description
- Create a beanDefinitionHolder that holds the correspondence between ABD and beanName and alias
- Handling a non-singleton Scope returns a proxy, as shown in the handling of @scope
- BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
Let’s look at step 9, how to register exactly:
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
Copy the code
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases ! = null) { for (String alias : aliases) { //TODO registry.registerAlias(beanName, alias); }}}Copy the code
As you can see, there are actually two parts of the registration:
- Registered beanName
- Register the alias
The registry is AnnotationConfigApplicationContext looked registerBeanDefinition method implementation:
Should be shown in the following, we call GenericApplicationContext the realization method of check:
Results found that still use DefaultListableBeanFactory for registration, It also demonstrates our conclusions about the relation between DefaultListableBeanFactory and AnnotationConfigApplicationContext above. To see how to realize in DefaultListableBeanFactory:
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition ! = null) { if (! isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (! beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; removeManualSingletonName(beanName); }} else {/ / Still in startup registration phase / / main look at this. Here beanDefinitionMap. Put (beanDefinition beanName); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition ! = null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); }}Copy the code
The above code checks whether the BD has been registered in the container, and then checks whether the DB is being registered. And we’re registering for the first time, so the core branch we’re going to go to is the else branch at line 59. The following things were done:
- BeanDefinitionMap has been placed with beanName as key
- BeanName is put into beanDefinitionNames
- If beanName exists in manualSingletonNames, remove it
Why maintain a separate beanDefinitionNames? Mainly because beanDefinitionMap is unordered, whereas beanDefinitionNames is an ArrayList, which is ordered and can hold bd’s registration order
What does the refresh method do
1.prepareRefresh
protected void prepareRefresh() { // Switch to active. this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) { logger.trace("Refreshing " + this); } else { logger.debug("Refreshing " + getDisplayName()); }} // Initialize any placeholder property sources in the context environment. // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners... if (this.earlyApplicationListeners == null) { this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { // Reset local application listeners to pre-refresh state. this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); }Copy the code
The pre-refresh phase mainly does the following things:
- Provide initPropertySources external resources () extension methods for container loading, the default is an empty implementation in AnnotationContextApplicationContext
- getEnvironment().validateRequiredProperties(); Validation of mandatory properties is provided by the AbstractPropertyResolver interface, of which the Environment object is an implementation.
@Override
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties) {
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) {
throw ex;
}
}
Copy the code
There are no mandatory attributes in the default container. If you need to add the validation, use the beanFactory to fetch the Environment and set it:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(SimpleConfig.class);
applicationContext.getEnvironment().setRequiredProperties("system");
applicationContext.refresh();
Copy the code
This is actually the following method of the AbstractPropertyResolver class called
@override public void setRequiredProperties(String... requiredProperties) { Collections.addAll(this.requiredProperties, requiredProperties); }Copy the code
RequiredProperties is a LinkedHashSet
private final Set<String> requiredProperties = new LinkedHashSet<>();
Copy the code
- Create earlyApplicationListeners, earlyApplicationEvents in the container
2.obtainFreshBeanFactory
Through the return value of this method can judge he obtained the container is built-in ConfigurableListableBeanFactory, we came to see him is how to obtain:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
Copy the code
Among them: GetBeanFactory () method is well understood, he is saved in GenericApplicationContext DefaultListableBeanFactory returns, The DefaultListableBeanFactor is instantiated in GenericApplicationContext empty constructor. Let’s see what the refreshBeanFactory() does:
@override protected final void refreshBeanFactory() throws IllegalStateException {// The internal container allows refresh only once if (! this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } this.beanFactory.setSerializationId(getId()); }Copy the code
The main CAS change has been made to refresh the container to ensure that the container is refreshed only once
3.prepareBeanFactory(beanFactory)
The preparation phase of the container
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); if (! ShouldIgnoreSpel) {// set the el expression parser (#{... }) the beanFactory. SetBeanExpressionResolver (new StandardBeanExpressionResolver (the beanFactory. GetBeanClassLoader ())); } / / set properties parser PropertyEditorRegistrar the beanFactory. AddPropertyEditorRegistrar (new ResourceEditorRegistrar (this, getEnvironment())); / / Configure the bean factory with the context callbacks. / / as the container, add a ApplicationContextAwareProcessor This is the first container to add BeanPostProcessor / / ApplicationContextAwareProcessor role: // Check whether the bean implements the following Aware interface. If so, The corresponding built-in bean or singleton object is assigned to the bean / / 1. EnvironmentAware - > applicationContext. GetEnvironment () / / 2. EmbeddedValueResolverAware - > embeddedValueResolver //3.ResourceLoaderAware -> applicationContext //4.ApplicationEventPublisherAware -> applicationContext //5.MessageSourceAware -> applicationContext //6.ApplicationContextAware -> applicationContext //7.ApplicationStartupAware -> applicationContext.getApplicationStartup() beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); 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.ignoreDependencyInterface(ApplicationStartupAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. 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 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. if (! NativeDetector.inNativeImage() && 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. // Inject the following singleton into the beanFactory 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()); } if (! beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) { beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup()); }}Copy the code
- Set this
- Set up the EL expression parser
- Set the PropertyEditorRegistrar
- Add a ApplicationContextAwareProcessor whether bean implements the following Aware interface, if implemented, The corresponding built-in bean or singleton object is assigned to the bean 1. EnvironmentAware – > applicationContext. GetEnvironment () 2. EmbeddedValueResolverAware – > embeddedValueResolver 3.ResourceLoaderAware -> applicationContext 4.ApplicationEventPublisherAware -> applicationContext 5.MessageSourceAware -> applicationContext 6.ApplicationContextAware -> applicationContext 7.ApplicationStartupAware -> applicationContext.getApplicationStartup()
- IgnoreDependencyInterface: ignore these interfaces when automatic assembly, implements the following interface, can set methods accept aware callback incoming values are assembled
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.ignoreDependencyInterface(ApplicationStartupAware.class);
Copy the code
- Add container built – in dependencies. < span style = “box-sizing: block; color: RGB (51, 51, 51); font-size: 14px! Important; word-break: break-all;” But if you specify a specific type of assembly object in resolvableDependencies, you can use the specified object directly. The Spring container has multiple antiphonic objects of type BeanFactory and so on, so the dependency object is specified here to avoid errors. We can also get the Beanfactory by customizing the BeanFactoryPostProcessor and then specifying our own type-dependent object relationship.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
Copy the code
- Add ApplicationListenerDetector DestructionAwareBeanPostProcessor: Bean exposure before the callback, before provide the bean instance, can return to replace beanMergedBeanDefinitionPostProcessor proxy objects
class ApplicationListenerDetector implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor {
Copy the code
- Register four singleton objects directly
// Register default environment beans. // Inject the following singleton object 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()); } if (! beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) { beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup()); }Copy the code
4.postProcessBeanFactory
Reserved extension method, not implemented by default
5.invokeBeanFactoryPostProcessors(beanFactory)
Here are two things to know about BeanFactoryPostProcesso:
- Registered spring BeanFactoryPostProcessor: ConfigurableApplicationContext# addBeanFactoryPostProcessor
- What BeanFactoryPostProcessor does:
@functionalInterface Public interface BeanFactoryPostProcessor {/** * Before all BeanDefinitions are loaded and no Bean is instantiated, This method allows you to modify the beanDefinition property configuration, You can even Modify the application context's internal bean factory after its standard * initialization definitions will have been loaded, but no beans * will have been instantiated yet. This allows for overriding or adding * properties even to eager-initializing beans. * @param beanFactory the bean factory used by the application context * @throws org.springframework.beans.BeansException in case of errors */ void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }Copy the code
In short, after the built-in BeanFactory is ready in Step 3. Give the user a chance to get to the beanFactory invokeBeanFactoryPostProcessors process, then we research the default container is not registered here spring BeanFactoryPostProcessor, but this method has other function
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 (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
Copy the code
getBeanFactoryPostProcessors()
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
Copy the code
PostProcessorRegistrationDelegate
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// WARNING: Although it may appear that the body of this method can be easily
// refactored to avoid the use of multiple loops and multiple lists, the use
// of multiple lists and multiple passes over the names of processors is
// intentional. We must ensure that we honor the contracts for PriorityOrdered
// and Ordered processors. Specifically, we must NOT cause processors to be
// instantiated (via getBean() invocations) or registered in the ApplicationContext
// in the wrong order.
//
// Before submitting a pull request (PR) to change this method, please review the
// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
// to ensure that your proposal does not result in a breaking change:
// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
// 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, beanFactory.getApplicationStartup());
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, beanFactory.getApplicationStartup());
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, beanFactory.getApplicationStartup());
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();
}
Copy the code
Main process:
- Create two list save spring BeanFactoryPostProcessor and BeanDefinitionRegistryPostProcessor respectively
- Store custom registered BeanFactoryPostProcessors to regularPostProcessors or registryProcessors by type, and: If it is BeanDefinitionRegistryPostProcessor call its postProcessBeanDefinitionRegistry method directly
- To create a new list to store the container built-in BeanDefinitionRegistryPostProcessor
- Through BeanDefinitionRegistryPostProcessor type and container PriorityOrdered gets the corresponding beans, add currentRegistryProcessors, and put the name in a processedBeans, Indicates that the command is executed. Here will get a: org. Springframework. Context. The annotation. InternalConfigurationAnnotationProcessor
- Will be ordered currentRegistryProcessors and into the registryProcessors
- Traversal of executive currentRegistryProcessors BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry method
- Here will perform internalConfigurationAnnotationProcessor callback method, this kind of follow-up will be special research, the result is that the configuration class @ Bean method corresponding class is registered as a bd loaded into the container
- Empty currentRegistryProcessors
- Repeat 4 to 8, calling is to realize the Ordered BeanDefinitionRegistryPostProcessor interface
- Repeat 4 to 8, call no BeanDefinitionRegistryPostProcessor sort interface
- Through the above operation, all BeanDefinitionRegistryPostProcessor joined registryProcessors, All custom BeanFactoryPostProcessors have been added to regularPostProcessors. Execute their postProcessBeanFactory method
- There are now container-built BeanFactoryPostProcessors that are not handled, but also load and call their postProcessBeanFactory methods in PriorityOrdered, Ordered, nonOrdered order
6.initMessageSource
MessageSource is listed as a panel discussion
7.initApplicationEventMulticaster()
Event broadcast mechanisms are included in the thematic discussion
8.onRefresh
By this point, the whole BeanFactory is ready to go. All that remains is the processing of the bean in the container, after which the onFresh method can perform the callback. In SpringBoot, for example, this method is used to start the embedded Web container
9.registerListeners()
- Register the built-in listener of the container
- Register a class that implements the ApplicationListener interface
10.inishBeanFactoryInitialization(beanFactory)
The process of instantiating all non-lazy-loaded singleton beans is again a very complex logic that we’ll discuss in Chapter 2
conclusion
After the above steps, the Spring container is initialized and the beanFactory is ready. The extended features provided by ApplicatiionContext: event mechanisms, resources, AOP, and other capabilities have also been initialized