All of the post-processors involved in the Bean life cycle and their execution timing

Here’s what you’ll learn from this article

  1. To understandBeanLife cycle process
  2. Know what back-end processors are available and wherebeanLifecycle their execution timing
  3. "Solid"dynamicdebug gif

  1. See a lot of work before you can align yourself with the interviewer

To understand this article, you should have a general idea of how Spring works, but don’t worry if you don’t

Those who are not familiar with the following process do not need to worry

The postProcessor in the execution process is primarily used to call at a point in time in a lifecycle

Now that I’m talking about it, you better Debug it

Now, there’s a big premise: Discussed here is that at the end of the container to refresh, you need to complete the Bean factory initialization callback (finishBeanFactoryInitialization, at the end of the callback will be preloaded Bean (preInstantiateSingletons), The logic of getBean is called to complete the initialization

The most important thing is to follow Debug, like your own Web project Debug

Want to download the source code to write test boots, if not, please let me know in the comments section below, I will make up the Spring source set up textbook oh!

If that’s too much trouble, I can upload my project to Gitee or Github, and everyone can pull it down and use it.

Okay, that’s it. Let’s get started

Take over the bean creation logic and return the custom bean

Starting with the getBean process, the class of the bean needs to be resolved in advance when the bean is created

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // If this bean has not been parsed, it will not have been parsed the first time
    if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.
        // Important!! If you don't want to read this paragraph, you can skip to the following if statement
        // Synthetic refers to whether the class is a Synthetic class. For example, when the class has an inner class, the inner class cannot access the private variables of the inner class
        // But what if the JVM wants support?
        // So it takes a strategy of creating a new class and combining it with the inner class to make it look like the programmer can access the inner class directly when he uses it
        // You can write your own class, see the class file, there will be a new xxx1.class
        if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// We can infer the class object from the method name
            // But how did he deduce itClass<? > targetType = determineTargetType(beanName, mbd);if(targetType ! =null) {
                // The post-processor is called. The built-in post-processor does nothing
                // Unless you have written your own post-processor, see the next code box
                // If your backend handler returns a bean to someone ahead of time, it will go directly to the following judgment to complete the initialization
                // If your company wants to implement the bean initialization process itself, it should do so here
                // Spring will then return the object directly, as shown below
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if(bean ! =null) {
                    // Perform post-processing at different times
                    // Below is a custom example, GIF demobean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean ! =null);
    }
    return bean;
}
Copy the code

  • It is worth mentioning that in addition to adding our own custom bean returns here, Spring will also delegate our custom bean if we enable automatic proxy. Interested students can add a custom bean to the configuration class@EnableAspectJAutoProxy, write aAspectThe section is assigned to usAClass try

Second, self-inference construction method

To create a bean, first create its object. How do you create the object? Create by constructor reflection? Yes, but if you offer more than one constructor, how do I know to use which constructor to create (next explanation, probably know here) Spring inference is carried out for the construction method, and logic inference is placed in the AutowiredAnnotationBeanPostProcessor to infer

protectedConstructor<? >[] determineConstructorsFromBeanPostProcessors(@NullableClass<? > beanClass, String beanName)throws BeansException {

    if(beanClass ! =null && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            / / can achieve SmartInstantiationAwareBeanPostProcessor determineCandidateConstructors for yourself
            / / to achieve coverage AutowiredAnnotationBeanPostProcessor complete customization
            if (bp instanceofSmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; Constructor<? >[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);if(ctors ! =null) {
                    returnctors; }}}}return null;
}
Copy the code

Spring by AutowiredAnnotationBeanPostProcessor constructor, we dig a pit, in the next special explain inference construction method.

Here we go. Here we go. Here we go

I’m sorry to interrupt you

Let’s write our own super simple custom post-processor implementation inference constructor to override Spring’s own inference method

@Component
public class CustomSmartInstantiationawareBPP implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    publicConstructor<? >[] determineCandidateConstructors(Class<? > beanClass, String beanName)throws BeansException {
        System.out.println("Deduce the constructors for yourself.");
        returnbeanClass.getDeclaredConstructors(); }}Copy the code

Results:

You can see that all the beans created are replaced with our custom ones

Merge beans

First let’s get one thing straight. What are merged beans? There are three BeanDefinitions in Spring

  1. RootBeanDefinitionFather BD
  2. ChildBeanDefinitionThe child BD
  3. GenericBeanDefinitionCan act on both parent BD and child BD

Now there is such a situation, similar to the Idea of Java inheritance, when a child BD inherits the parent BD, the child BD can be used to manipulate the parent class attributes (the child inherits the parent class). So you have to merge BD so that the subclass also has the attributes of the parent class

Father and son BD explained. Then why not use GenericBD directly, perhaps for historical reasons, the current version must be forward compatible, so must be retained.

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    finalObject bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; }// Allow post-processors to modify the merged bean definition.
    The beanPostProcessor (beanPostProcessor, beanPostProcessor, beanPostProcessor, beanPostProcessor, beanPostProcessor, beanPostProcessor, beanPostProcessor, beanPostProcessor
    synchronized (mbd.postProcessingLock) {
        if(! mbd.postProcessed) {try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true; · · · · · · ·}}}protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class
        beanType, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceofMergedBeanDefinitionPostProcessor) { MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp; bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName); }}}Copy the code

PostConstruct CommonAnnotationBeanPostProcessor, mainly for life cycle and the PreDestroy breakthrough point and resources into @ Resource XML WebServiceRef and EJB

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class
        beanType, String beanName) {
    // Go through all the methods, find all the @postConstruct and @PreDestroy methods and put them in BD. Put them in BD's checkedInitMethods and checkedDestroyMethods properties
    / / here is to call the superclass "InitDestroyAnnotationBeanPostProcessor" method
    super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
    / / to iterate through all fields and methods, find all @ the Resource and javax.mail XML. Ws. WebServiceRef and javax.mail ejb. The ejb in the bd checkedElements attribute them
    InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}
Copy the code

AutowiredAnnotationBeanPostProcessor, mainly for all took the @autowired properties and methods (static regardless of the method are not eligible)

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class
        beanType, String beanName) {
    // Find all fields and annotations with @autoWired and place them in BD's checkedElements
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}
Copy the code

Next, we implement a post-processor ourselves, find an annotation that we define ourselves, and store it in BD as well

@Component
public class CustomMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
    // Simulate the AutoWired annotation parsing process
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class
        beanType, String beanName) {
        // The first step is to find the annotation and encapsulate the information
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        // The second step is to inject the annotation information into bd
        metadata.checkConfigMembers(beanDefinition);
    }

    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

    // Do something similar to autowired
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<? > clazz,@Nullable PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    if(metadata ! =null) {
                        metadata.clear(pvs);
                    }
                    metadata = buildAutowiringMetadata(clazz);
                    this.injectionMetadataCache.put(cacheKey, metadata); }}}return metadata;
    }

    private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
        List<InjectionMetadata.InjectedElement> elements = newArrayList<>(); Class<? > targetClass = clazz;do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            // Find all the fields with the fields
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                if (field.isAnnotationPresent(ZWL.class)) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        return;
                    }
                    boolean required = field.getAnnotation(ZWL.class).required();
                    String requiredStr = required? "Losing":"You have to lose.";
                    // It is used to store annotation information so that the next time you need to inject it, you can inject it through the element
                    System.out.println("Find a ZWL annotation in" + clazz.getSimpleName() + "Of the class, yes" + requiredStr + "The");
                    currElements.add(newZWLFieldElement(field, required)); }}); elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }
        while(targetClass ! =null&& targetClass ! = Object.class);InjectionMetadata (); // Return the information parsed after encapsulation
        return new InjectionMetadata(clazz, elements);
    }

    private class ZWLFieldElement extends InjectionMetadata.InjectedElement {

        private final boolean required;

        private volatile boolean cached = false;

        @Nullable
        private volatile Object cachedFieldValue;

        public ZWLFieldElement(Field field, boolean required) {
            super(field, null);
            this.required = required;
        }

        @Override
        protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
            / / into the bean}}}Copy the code

Below is the Debug GIF of conscience

Use factories to expose proxy objects in advance

As we in the previous article, circular dependencies mentioned, the portal, in the process – A – > B > A to B into A object, if you have been A agent, so have to give him into A proxy object, so this place is to be produced by the factory, the factory works, is through A proxy object returned by the post processor

Code, as clear as day

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null&& allowEarlyReference) { ObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName);
                if(singletonFactory ! =null) {
                    // Call the factory method to produce
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName); }}}}return singletonObject;
}

// Factory method
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                / / so much in the post processor have AnnotationAwareAspectJAutoProxyCreator getEarlyBeanReference method creates a proxy objectsSmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); }}}return exposedObject;
}

Copy the code

Serious dividing line, warning! The next two post-processor execution times are performed when the property is injected


5, Before the bean injection properties, you can make some judgment changes to the bean, or directly interrupt the bean property injection (determine whether to continue to inject properties).

// Spring's built-in beanPostProcessor does nothing here
// So we can only define one
if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation =false;
                break; }}}}/ / to have a look at our custom example, reuse the previous CustomInstantiationAwareBPP here
@Component
public class CustomInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
    Object result = null;
    if (beanName.equals("A")) {
        System.out.println("Let's do an A before we initialize it.");
        result = new ObjectA();
    }
    // Avoid returning custom objects and end bean creation
    // return result;
    return null;
}

// New ones are here!!
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    System.out.println("Before the property is actually injected." + beanName + "Bean does little things.");
    // Whether to continue injecting attributes, true continues
    return true;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (beanName.equals("A")) {
        System.out.println("A's done. All right, take it.");
    }
    returnbean; }}Copy the code

The result, of course, is this sentence printed

Property injection

The execution point of the post-processor

PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
    if (pvs == null) {
        pvs = mbd.getPropertyValues();
    }
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // Modify the bean propertyValues
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                if (filteredPds == null) {
                    filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                }
                // This method has been abandoned and is not recommended
                pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return; } } pvs = pvsToUse; }}}Copy the code

Here go into CommonAnnotationBeanPostProcessor mentioned before @ the properties of the Resource, WebServiceRef, EJB or the setting of the method is called

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    // Find @resource and other information. If you have parsed it before, you will not parse it
    InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
    try {
        // The properties were injected into BDS last time, this time into beans
        metadata.inject(bean, beanName, pvs);
    } catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
    }
    return pvs;
}
Copy the code

The same AutowiredAnnotationBeanPostProcessor and complete property into here, the code logic here is to find the @autowired properties or methods And then find its proper value and then injected, as to how to find the value of this knowledge next article explanation

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        metadata.inject(bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}
Copy the code

Finally, according to the order of our own post processor, or continue to use before CustomInstantiationAwareBPP

@Component
public class CustomInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {

@Override
public Object postProcessBeforeInstantiation(Class
        beanClass, String beanName) throws BeansException {
    Object result = null;
    if (beanName.equals("A")) {
        System.out.println("Let's do an A before we initialize it.");
        result = new ObjectA();
    }
    // Avoid returning custom objects and end bean creation
    // return result;
    return null;
}

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    System.out.println("Before the property is actually injected." + beanName + "Bean does little things.");
    // Whether to continue injecting attributes, true continues
    return true;
}

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    System.out.println("Modify the bean's PropertyValues and inject the corresponding properties.");
    return pvs;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (beanName.equals("A")) {
        System.out.println("A's done. All right, take it.");
    }
    returnbean; }}Copy the code

It’s time to draw the dividing line again, and that’s where the hunk should be looking

Multi-picture warning!!


That’s what it’s usually about. Let’s move on

The next step is when to initialize the bean after it has completed property injection

7. Call various aware before initialization

Let’s first look at the call logic for initializing the whole

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // Call the bean's aware method
    if(System.getSecurityManager() ! =null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    // called before initialization
    Object wrappedBean = bean;
    if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }try {
        // Call the implemented initialization method
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw newBeanCreationException( (mbd ! =null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    // called after initialization
    if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }return wrappedBean;
}
Copy the code

Initialize the previous pointcut

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}
Copy the code

First see ApplicationContextAwareProcessor mainly to trigger some implements environmental event listeners, resource load ` ` information release, etc. The event interface

@Override
@Nullable
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();
    }
    // This acc is aware related to resources and environment. DoPrivileged is required for implementation
    if(acc ! =null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareInterfaces(bean);
            return null;
        }, acc);
    }
    else {
        invokeAwareInterfaces(bean);
    }

    return bean;
}

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); }}}Copy the code

After all environment-specific interfaces are invoked, the custom post-processor starts executing

@Component
public class CustomInstantiationAwareBPP implements InstantiationAwareBeanPostProcessor {
// Same class, familiar flavor, with the bean's entire instantiation life cycle
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (beanName.equals("A")) {
        System.out.println("Before actually initializing, modify bean A.");
    }
    return bean;
}

// Other lifecycle call methods
}
Copy the code

Remember when we said earlier CommonAnnotationBeanPostProcessor merger bean, also is the post processor, Will call its superclass InitDestroyAnnotationBeanPostProcessor @ PostConstruct and @ PreDestroy method of annotation to the current post processor, the following is to invoke them

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // Find the previously found '@postconstruct' and '@predestroy'
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        // Execute them
        metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
}
Copy the code

Eighth, after completing the initialization of the bean – complete the proxy

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}
Copy the code

I’m not going to post a custom post-processor here, just like before

The first post-processor isPostProcessorRegistrationDelegate

He first checks that the bean currently being created is not BeanPostProcessor, not spring’s base type bean, and!! Here’s the important thing: If the number of all bean postprocessors in the current factory is less than the actual number of postprocessors executed, an INFO is typed, where a lot of people stomp. Take a look at the code:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    if(! (beaninstanceofBeanPostProcessor) && ! isInfrastructureBean(beanName) &&this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
        if (logger.isInfoEnabled()) {
            logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() +
                    "] is not eligible for getting processed by all BeanPostProcessors " +
                    "(for example: not eligible for auto-proxying)"); }}return bean;
}
Copy the code

Step in what hole? For example, if you look at the log below, Spring says that your current bean is not ready to be called by any post-processor, such as auto-propping (causing the propping to fail).

This is why so many people suddenly find their projects, transactions, AOP, or async broken, and get blindsided.

How do you solve it?

For example, if you don’t want to open a configuration class of your own to save trouble, use a lower priority BeanPostProcessor (such as a low order one) in the previous project code to do the injection of the business bean. When this bean is injected, since the transaction/AOP post-processor has not yet been loaded, it naturally does not issue the proxy to the bean, making them appear invalidated

In human terms, you instantiate your business bean in front of Spring’s back processor

The solution is, don’t be lazy, create your own configuration class to put in, make sure to execute later ok

The second is Abstracta toProxyCreator

If A->B->A, if A needs to be proxied, then earlyProxyReferences will have A cache of A to complete the proxiing here

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if(bean ! =null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) ! = bean) {returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
}
Copy the code

The last is ApplicationListenerDetector plays the role

Actually see one line of code here enclosing applicationContext. AddApplicationListener ((ApplicationListener <? >) bean);

Put the listener in the environment

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (bean instanceof ApplicationListener) {
        // potentially not detected as a listener by getBeanNamesForType retrieval
        Boolean flag = this.singletonNames.get(beanName);
        if (Boolean.TRUE.equals(flag)) {
            // singleton bean (top-level or inner): register on the fly
            this.applicationContext.addApplicationListener((ApplicationListener<? >) bean); }else if (Boolean.FALSE.equals(flag)) {
            if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
                // inner bean with other scope - can't reliably process events
                logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
                        "but is not reachable for event multicasting by its containing ApplicationContext " +
                        "because it does not have singleton scope. Only top-level listener beans are allowed " +
                        "to be of non-singleton scope.");
            }
            this.singletonNames.remove(beanName); }}return bean;
}
Copy the code

Pa pa pa finally tm finished writing

After that comes some finishing touches to getBeans, clearing the cache, adding beans to the singleton pool, and so on

In the next article we will fill in the hole above – how do we infer the constructor of a bean when creating it