All of the post-processors involved in the Bean life cycle and their execution timing
Here’s what you’ll learn from this article
- To understand
Bean
Life cycle process - Know what back-end processors are available and where
bean
Lifecycle their execution timing "Solid"
的dynamic
的debug
gif
- 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 aAspect
The section is assigned to usA
Class 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
RootBeanDefinition
Father BDChildBeanDefinition
The child BDGenericBeanDefinition
Can 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