preface
- Last blogSpring 5.0 x source of learning six series: post processor ConfigurationClassPostProcessor BeanDefinitionRegistryPostProcessor identityMainly introducedConfigurationClassPostProcessortheBeanDefinitionRegistryPostProcessorIdentity. In order to master Spring, we also need a second identity for it
BeanFactoryPostProcessor
summarized
A, the spring BeanFactoryPostProcessor ConfigurationClassPostProcessor identity
- Its identity also serves a very important purpose: adding a Cglib proxy to a fully configured class prevents the problem of repeatedly calling the same logic when creating beans as @beans. Let’s explore it with the following demo.
Ii. Project Demo
2.1 Project Panorama
2.1.1 AppConfig
2.1.2 Bean1
2.1.3 Bean2
2.1.4 Entry
2.2 Running Results
2.2.1 Running result of no @Configuration annotation in AppConfig Class
2.2.1 Running result of @Configuration annotation in AppConfig class
2.3 Explaining the Running results
situation | The results | why |
---|---|---|
There is no @Configuration annotation in AppConfig | Print “Creating Bean1” twice | Spring Bean1 creates Bean1; Spring Bean2 creates Bean1; Spring Bean1 creates Bean1 |
The @Configuration annotation exists in AppConfig | I only print “Creating Bean1” once | Because spring executes the BeanFactoryPostProcessor post-processor. Perform the ConfigurationClassPostProcessor postProcessBeanFactory method, this method of annotation category of all the additional agents, the method has been enhanced, The class of cglib is now added to the beanClass property of the beanDefinition corresponding to the current fully configured class. |
2.4 Viewing the Cglib Agent Content
2.4.1 Setting specified properties to save the Cglib proxy class to the specified location
// Save all the cglib agent classes generated in the whole project to the cglib folder on disk G
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "g://cglib");
Copy the code
2.4.2 Run the project and view the folder
2.4.3 Copy the com folder to the directory that can parse class files in IDEA
-
Since Spring source code is compiled using Gradle, I copy it into the out folder. For a regular Maven project, I copy it into the target folder
-
The generated proxy class folder structure is as follows:
-
Proxy class source code:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3; import java.lang.reflect.Method; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.cglib.core.ReflectUtils; import org.springframework.cglib.core.Signature; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import org.springframework.cglib.proxy.NoOp; import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration; /** * It inherits from AppConfig, so it is the Cglib proxy for AppConfig */ public class AppConfig$$EnhancerBySpringCGLIB$$912e823e extends AppConfig implements EnhancedConfiguration { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private MethodInterceptor CGLIB$CALLBACK_1; private NoOp CGLIB$CALLBACK_2; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$bean1$0$Method; private static final MethodProxy CGLIB$bean1$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$bean2$1$Method; private static final MethodProxy CGLIB$bean2$1$Proxy; private static final Method CGLIB$setBeanFactory$6$Method; private static final MethodProxy CGLIB$setBeanFactory$6$Proxy; public BeanFactory $$beanFactory; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3.AppConfig$$EnhancerBySpringCGLIB$$912e823e"); Class var1; CGLIB$setBeanFactory$6$Method = ReflectUtils.findMethods(new String[]{"setBeanFactory"."(Lorg/springframework/beans/factory/BeanFactory;) V"}, (var1 = Class.forName("org.springframework.beans.factory.BeanFactoryAware")).getDeclaredMethods())[0]; CGLIB$setBeanFactory$6$Proxy = MethodProxy.create(var1, var0, "(Lorg/springframework/beans/factory/BeanFactory;) V"."setBeanFactory"."CGLIB$setBeanFactory$6"); Method[] var10000 = ReflectUtils.findMethods(new String[]{"bean1"."()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;"."bean2"."()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;"}, (var1 = Class.forName("com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3.AppConfig")).getDeclaredMethods()); CGLIB$bean1$0$Method = var10000[0]; CGLIB$bean1$0$Proxy = MethodProxy.create(var1, var0, "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;"."bean1"."CGLIB$bean1$0"); CGLIB$bean2$1$Method = var10000[1]; CGLIB$bean2$1$Proxy = MethodProxy.create(var1, var0, "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;"."bean2"."CGLIB$bean2$1"); } final Bean1 CGLIB$bean1$0() { return super.bean1(); } /** * Proxy enhanced bean1 method */ public final Bean1 bean1(a) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } returnvar10000 ! =null ? (Bean1)var10000.intercept(this, CGLIB$bean1$0$Method, CGLIB$emptyArgs, CGLIB$bean1$0$Proxy) : super.bean1(); } final Bean2 CGLIB$bean2$1() { return super.bean2(); } /** * Proxy enhanced bean2 method */ public final Bean2 bean2(a) { // Here is the method interceptor for generating the Cglib proxy class // The default method interceptors in Spring have these three: // private static final Callback[] CALLBACKS = new Callback[] { // new BeanMethodInterceptor(), // new BeanFactoryAwareMethodInterceptor(), // NoOp.INSTANCE // }; // The method interceptor is an enhanced bean2 method MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } returnvar10000 ! =null ? (Bean2)var10000.intercept(this, CGLIB$bean2$1$Method, CGLIB$emptyArgs, CGLIB$bean2$1$Proxy) : super.bean2(); } final void CGLIB$setBeanFactory$6(BeanFactory var1) throws BeansException { super.setBeanFactory(var1); } public final void setBeanFactory(BeanFactory var1) throws BeansException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_1; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_1; } if(var10000 ! =null) { var10000.intercept(this, CGLIB$setBeanFactory$6$Method, new Object[]{var1}, CGLIB$setBeanFactory$6$Proxy); } else { super.setBeanFactory(var1); }}public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -1792804773: if (var10000.equals("bean2()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;")) { return CGLIB$bean2$1$Proxy; } break; case 720662557: if (var10000.equals("bean1()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;")) { return CGLIB$bean1$0$Proxy; } break; case 2095635076: if (var10000.equals("setBeanFactory(Lorg/springframework/beans/factory/BeanFactory;) V")) { return CGLIB$setBeanFactory$6$Proxy; }}return null; } public AppConfig$$EnhancerBySpringCGLIB$$912e823e() { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) { CGLIB$THREAD_CALLBACKS.set(var0); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) { CGLIB$STATIC_CALLBACKS = var0; } private static final void CGLIB$BIND_CALLBACKS(Object var0) { AppConfig$$EnhancerBySpringCGLIB$$912e823e var1 = (AppConfig$$EnhancerBySpringCGLIB$$912e823e)var0; if(! var1.CGLIB$BOUND) { var1.CGLIB$BOUND =true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if (var10000 == null) { return; } } Callback[] var10001 = (Callback[])var10000; var1.CGLIB$CALLBACK_2 = (NoOp)((Callback[])var10000)[2]; var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1]; var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0]; }}static { CGLIB$STATICHOOK2(); CGLIB$STATICHOOK1(); } static void CGLIB$STATICHOOK2() { } } Copy the code
Third, summary
- ConfigurationClassPostProcessor spring BeanFactoryPostProcessor identity of the annotation for the most important thing is to add additional agent. In addition to this, of course, also registered a type for ImportAwareBeanPostProcessor BeanPostProcessor, has not yet concluded it good here.
- I am a slow walker, but I never walk backwards.
- Github SpringGithub.com/AvengerEug/…