揭秘@Configuration的秘密之BeanFactory后置处理器

前序文章 Spring如何扫描工作目录下的Bean?|图文并茂讲解@Configuration的工作原理

文章目录

  • 揭秘@Configuration的秘密之BeanFactory后置处理器
    • 基础介绍
      • 目的
    • 流程图
    • 代码分析
      • (1) postProcessBeanFactory()
      • (2)enhanceConfigurationClasses()
      • (3)ConfigurationClassEnhancer.enhance()
      • (4)ConfigurationClassEnhancer.newEnhancer()
      • (5)ConfigurationClassEnhancer.createClass()
    • 特别分析
      • BeanMethodInterceptor.class
        • Bean案例
        • FactoryBean
      • BeanFactoryAwareMethodInterceptor.class
    • 谨防入坑
      • FactoryBean注入进Spring后,其BeanName真的是&FactoryBean吗?
      • FactoryBean中getObject()对象什么时候注入进Spring中的?
      • 如果@Configuration被换成了@Component,@Bean方法还会生成单例吗?

基础介绍

前面我们已经探究了@Configuration的原理 Spring如何扫描工作目录下的Bean?|图文并茂讲解@Configuration的工作原理。实际上是ConfigurationClassPostProcessor.class在背后承担了重量级的地位。该类继承了BDR后置处理器,而且BDR后置处理器又继承了BF后置处理器。本文将探究继承了BF后置处理器,它实现了怎么样的逻辑;

目的
@Configuration
public MyConfiguration {@Beanpublic MyBean createMyBean() {return new MyBean();}@Beanpublic MySubBean createSubBean() {// 此时createMyBean()只会new一次return new MySubBean(createMyBean());}
}

在配置类中,有许多地方声明了@Bean方法,Spring中的bean默认情况下都是单例的,那么如果又有方法调用了@Bean的方法,例如上面的代码,createSubBean()方法中又调用了createMyBean()方法。如何保证bean只会被new一次呢?

Spring在处理@Configuration的配置类时,实际上是给他增加了一个CGLIB代理,放入SpringBean中的配置类实例实际上是一个被代理的对象。当第一次调用createMyBean()方法时,会执行new方法,创建出对象。那么再一次调用createMyBean()方法时,就会去bean工厂中的beanMap中去取,因此保证了单例模型;

流程图

invokeBeanFactoryPostProcessors()方法中,首先执行:

BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(registry);

然后再执行:

BeanFactoryPostProcessor.postProcessBeanFactory(beanFactory);

前文中,首先执行的是扫描所有的bd,将项目中所有的类都扫描成bd放进beanFactory中;那么接下来就要将所有的bd取出,筛选出上面加了@Configuration的bd,将其通过cglib进行代理;

代码分析

(1) postProcessBeanFactory()

该类就是bf后置处理器需要实现的方法,在该方法中,就是将配置类进行cglib代理(见方法2),之后再放入一个Bean的后置处理器ImportAwareBeanPostProcessor.class;

// ConfigurationClassPostProcessor.class
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {int factoryId = System.identityHashCode(beanFactory);if (this.factoriesPostProcessed.contains(factoryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + beanFactory);}this.factoriesPostProcessed.add(factoryId);if (!this.registriesPostProcessed.contains(factoryId)) {// BeanDefinitionRegistryPostProcessor hook apparently not supported...// Simply call processConfigurationClasses lazily at this point then.processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);}// 将配置类进行cglib代理enhanceConfigurationClasses(beanFactory);beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
(2)enhanceConfigurationClasses()

该方法首先取出所有的bd,依次遍历,筛选出加了@Configuration的bd;

创建ConfigurationClassEnhancer配置类代理增强器,后面就通过该增强器去给配置类设置代理;

循环配置类bd,通过配置类代理增强器对bd进行代理enhancer.enhance(),见方法3

配置类bd设置setBeanClass为代理类class,后续实例化bean的时候,就创建的代理类的对象;

// ConfigurationClassPostProcessor.class
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();for (String beanName : beanFactory.getBeanDefinitionNames()) {BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);// 将加了@Configuration的配置类放入configBeanDefsif (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {if (!(beanDef instanceof AbstractBeanDefinition)) {throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +beanName + "' since it is not stored in an AbstractBeanDefinition subclass");}// 如果该bd被实例化了则需要将其中@Bean设置为静态的else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {logger.warn("Cannot enhance @Configuration bean definition '" + beanName +"' since its singleton instance has been created too early. The typical cause " +"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +"return type: Consider declaring such methods as 'static'.");}configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);}}if (configBeanDefs.isEmpty()) {// nothing to enhance -> return immediatelyreturn;}// 定义配置类增强器ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {AbstractBeanDefinition beanDef = entry.getValue();// If a @Configuration class gets proxied, always proxy the target classbeanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);try {// Set enhanced subclass of the user-specified bean class// 根据类加载器获取出的配置类class,后面直接进行代理Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);if (configClass != null) {Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);if (configClass != enhancedClass) {// bd设置最终实例化对象就是这个被代理类beanDef.setBeanClass(enhancedClass);}}}catch (Throwable ex) {throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);}}
}
(3)ConfigurationClassEnhancer.enhance()

配置类增强器的enhance()方法,他判断该class是否实现了EnhancedConfiguration.class接口,因为如果是被代理的,都会实现这个接口;如果已实现,则表示已经被代理过,直接返回即可;

给class创建一个代理class见方法4,然后再返回代理类class见方法5,最终将代理class返回出去,让外层方法设置进bd中;

// ConfigurationClassEnhancer.class
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {// 如果class的父类是EnhancedConfiguration,则不需要进行代理if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {return configClass;}// 设置被代理的类classClass<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));return enhancedClass;
}
(4)ConfigurationClassEnhancer.newEnhancer()

这个方法就是创建一个cglib代理,我们可以看出,他是通过继承的方式实现代理,然后需要实现EnhancedConfiguration.class接口去标识他已经被代理;

最关键的是他实现了两个回调接口BeanMethodInterceptor.classBeanFactoryAwareMethodInterceptor.class,他们是用来处理@Bean返回的对象以及factoryBean;

// ConfigurationClassEnhancer.class
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(configSuperClass);// cglib是通过是否实现EnhancedConfiguration接口判断是否有被代理enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});enhancer.setUseFactory(false);enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));// 设置了两个关键的回调函数enhancer.setCallbackFilter(CALLBACK_FILTER);enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());return enhancer;
}// 关键方法 回调接口
private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
private static final Callback[] CALLBACKS = new Callback[] {new BeanMethodInterceptor(),new BeanFactoryAwareMethodInterceptor(),NoOp.INSTANCE
};
(5)ConfigurationClassEnhancer.createClass()

就是给代理的class设置CALLBACKS;可以看看我代码中的注释。

这里附上了被代理类的代码,需要保存被CGLIB类可以在java代码中加入该代码:

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\cglib");
private Class<?> createClass(Enhancer enhancer) {// 获取被代理的类classClass<?> subclass = enhancer.createClass();// Registering callbacks statically (as opposed to thread-local)// is critical for usage in an OSGi environment (SPR-5932)...// 代理类中包含一个静态方法// public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callback);// 将CALLBACKS设置其中Enhancer.registerStaticCallbacks(subclass, CALLBACKS);return subclass;
}
// 被CGLIB代理后的配置类
public class SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa extends SpringstudyApplication 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$setBeanFactory$4$Method;private static final MethodProxy CGLIB$setBeanFactory$4$Proxy;private static final Object[] CGLIB$emptyArgs;public BeanFactory $$beanFactory;static void CGLIB$STATICHOOK1() {CGLIB$THREAD_CALLBACKS = new ThreadLocal();CGLIB$emptyArgs = new Object[0];Class var0 = Class.forName("cn.ixp.springstudy.SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa");Class var1;CGLIB$setBeanFactory$4$Method = ReflectUtils.findMethods(new String[]{"setBeanFactory", "(Lorg/springframework/beans/factory/BeanFactory;)V"}, (var1 = Class.forName("org.springframework.beans.factory.BeanFactoryAware")).getDeclaredMethods())[0];CGLIB$setBeanFactory$4$Proxy = MethodProxy.create(var1, var0, "(Lorg/springframework/beans/factory/BeanFactory;)V", "setBeanFactory", "CGLIB$setBeanFactory$4");}final void CGLIB$setBeanFactory$4(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$4$Method, new Object[]{var1}, CGLIB$setBeanFactory$4$Proxy);} else {super.setBeanFactory(var1);}}public static MethodProxy CGLIB$findMethodProxy(Signature var0) {String var10000 = var0.toString();switch(var10000.hashCode()) {case 2095635076:if (var10000.equals("setBeanFactory(Lorg/springframework/beans/factory/BeanFactory;)V")) {return CGLIB$setBeanFactory$4$Proxy;}}return null;}public SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa() {CGLIB$BIND_CALLBACKS(this);}public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {CGLIB$THREAD_CALLBACKS.set(var0);}// 这里设置静态的callback集合public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {CGLIB$STATIC_CALLBACKS = var0;}private static final void CGLIB$BIND_CALLBACKS(Object var0) {SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa var1 = (SpringstudyApplication$$EnhancerBySpringCGLIB$$26a254aa)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() {}
}

特别分析

上面我们分析了postProcessBeanFactory()方法的执行流程。那么在过程中,有两个特殊的Callbacks需要我们关注,那么我们来分析一下这两个特别的callbacks;

private static final Callback[] CALLBACKS = new Callback[] {new BeanMethodInterceptor(),new BeanFactoryAwareMethodInterceptor(),NoOp.INSTANCE
};
BeanMethodInterceptor.class

当代理类对象调用方法的时候,就会进入intercept()方法,做方法拦截。代码的具体流程可以看我加的注释,这个方法的具体流程见后续分析;

@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) throws Throwable {// 获取bean工厂ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);// 如果有获取@Bean,就获取bean的名称——返回的要不是bean名称,要么就是方法名String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);// Determine whether this bean is a scoped-proxy// 作用域Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class);if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {beanName = scopedBeanName;}}// To handle the case of an inter-bean method reference, we must explicitly check the// container for already cached instances.// First, check to see if the requested bean is a FactoryBean. If so, create a subclass// proxy that intercepts calls to getObject() and returns any cached bean instance.// This ensures that the semantics of calling a FactoryBean from within @Bean methods// is the same as that of referring to a FactoryBean within XML. See SPR-6602.// 判断有没有循环调用返回factoryBean的方法,如果有的话则对该factoryBean方法创建代理if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&factoryContainsBean(beanFactory, beanName)) {Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);if (factoryBean instanceof ScopedProxyFactoryBean) {// Scoped proxy factory beans are a special case and should not be further proxied}else {// It is a candidate FactoryBean - go ahead with enhancement// 给getObject()方法增加代理return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);}}// 比如代码 a(){ return new a();} b(){ return a()}// (1)首先a访问到这isCurrentlyInvokedFactoryMethod()返回true,然后就直接执行new a()// (2)然后b访问到这isCurrentlyInvokedFactoryMethod()返回true,然后直接执行a()方法// (3)这次再调用a()方法时,isCurrentlyInvokedFactoryMethod()返回false,就不执行new a()了// isCurrentlyInvokedFactoryMethod解析:// 他会获取当前调用的方法currentlyInvokedMethod 和将要执行的方法 method// 当currentlyInvokedMethod==method时返回true// 因此(3)这块,currentlyInvokedMethod是b(),而执行的method是a(),因此返回falseif (isCurrentlyInvokedFactoryMethod(beanMethod)) {// The factory is calling the bean method in order to instantiate and register the bean// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually// create the bean instance.if (logger.isWarnEnabled() &&BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {logger.warn(String.format("@Bean method %s.%s is non-static and returns an object " +"assignable to Spring's BeanFactoryPostProcessor interface. This will " +"result in a failure to process annotations such as @Autowired, " +"@Resource and @PostConstruct within the method's declaring " + "@Configuration class. Add the 'static' modifier to this method to avoid " +"these container lifecycle issues; see @Bean javadoc for complete details.", beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));}return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);}// 直接从bean工厂里取,不再重新newreturn resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
Bean案例

拿文章开头的demo来分析。

@Configuration
public MyConfiguration {@Beanpublic MyBean createMyBean() {return new MyBean();}@Beanpublic MySubBean createSubBean() {// 此时createMyBean()只会new一次return new MySubBean(createMyBean());}
}

当实例化MyBean的bd的时候,我们调用的就是MyConfiguration.createMyBean()方法。这时就会被方法拦截,通过isCurrentlyInvokedFactoryMethod()方法来判断是否是第一次创建MyBean对象。

private boolean isCurrentlyInvokedFactoryMethod(Method method) {Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}

这个方法有一个Method是currentlyInvoked,他表示当前调用该方法的方法,例如当前是createMyBean();

入口参数Method是method,他表示当前需要执行的方法;执行的是createMyBean();

当调用方法=执行方法,返回true,则可表示当前是第一次执行new对象,否则就不是第一次执行new对象;

因此MyBean的bd实例化走的是new MyBean()创建对象;

而实例化MySubBean的bd时,里面调用了createMyBean(),这时进入isCurrentlyInvokedFactoryMethod方法返回的是false,因为调用方法是createSubBean(),执行方法createMyBean(),因此这里是去beanFactory取MyBean的实例化对象;

总结:配置类中的@Bean(单例下)方法,多次调用只会实例化一次,后面都会从bean工厂中取已实例化的对象。

FactoryBean

先上demo

@Configuration
public class MyBeanConfig {// 放入Bean容器中@Beanpublic MyFactoryBean getMyFactoryBean() {return new MyFactoryBean();}@Beanpublic MyFactoryBean getMySameFactoryBean() {return getMyFactoryBean();}
}
// 定义的FactoryBean
public class MyFactoryBean implements FactoryBean<MyBean> {@Overridepublic MyBean getObject() throws Exception {return new MyBean();}@Overridepublic Class<?> getObjectType() {return MyBean.class;}
}
// 定义的Bean
public class MyBean {public MyBean() {System.out.println("创建了 MyBean");}
}

这里的流程是这样的:

  1. 执行getMyFactoryBean()方法时,第一次进入时不会走下面的代码,而是和@Bean的流程一样,判断当前调用方法和执行方法是否一样,这里为true,执行new MyFactoryBean();

     // 判断有没有循环调用返回factoryBean的方法,如果有的话则对该factoryBean方法创建代理
    if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&factoryContainsBean(beanFactory, beanName)) {Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);if (factoryBean instanceof ScopedProxyFactoryBean) {// Scoped proxy factory beans are a special case and should not be further proxied}else {// It is a candidate FactoryBean - go ahead with enhancement// 给getObject()方法增加代理return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);}
    }
  2. 接下来执行getMySameFactoryBean(),这里也是执行到判断当前调用方法和执行方法是否一样,这里为true,执行getMyFactoryBean();

    return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
  3. 由于又去执行getMyFactoryBean();这时再一次进入方法拦截器中,这次会走这块的代码了。

    factoryContainsBean()判断的是beanName=getMyFactoryBean是不是FactoryBean,其原理是getMyFactoryBean是不是已经在beanFactory中了,且是FactoryBean;

    我们都知道,factoryBean在bean容器中都是以&为前缀的,【但并不是其beanName加了&】,后面会去解释;

    这里第一次判断factoryContainsBean(beanFactory,“&” + beanName)我还不太明白,因为factoryContainsBean()对于beanName是取了去除&的,然后对于单例已创建的Bean是判断是否实现了FactoryBean.class接口,这里需要再探究!!!

     // 判断有没有循环调用返回factoryBean的方法,如果有的话则对该factoryBean方法创建代理
    if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&factoryContainsBean(beanFactory, beanName)) {Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);if (factoryBean instanceof ScopedProxyFactoryBean) {// Scoped proxy factory beans are a special case and should not be further proxied}else {// It is a candidate FactoryBean - go ahead with enhancement// 给getObject()方法增加代理return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);}
    }

    然后创建了CGLIB代理MyFactoryBean.class并返回;我们可以看到,代理的方法拦截主要是如果调用getObject()方法从工厂里取,其余方法都是反射原代理对象的方法

    ((Factory) fbProxy).setCallback(0, (MethodInterceptor) (obj, method, args, proxy) -> {if (method.getName().equals("getObject") && args.length == 0) {return beanFactory.getBean(beanName);}return proxy.invoke(factoryBean, args);
    });

    因此,我们从实验结果上可以看出,&getMyFactoryBean返回的对象是MyFactoryBean,而&getMySameFactoryBean返回的是MyFactoryBean代理对象,且被代理的对象就是MyFactoryBean;

BeanFactoryAwareMethodInterceptor.class

这个方法拦截器只拦截setBeanFactory()方法,它主要是设置了$$beanFactory为args[0],另外如果该代理类实现了BeanFactoryAware.class则调用setBeanFactory(args)方法;

private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {@Override@Nullablepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 取出代理类中的$$beanFactoryField field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);Assert.state(field != null, "Unable to find generated BeanFactory field");// 设置$$beanFactoryfield.set(obj, args[0]);// Does the actual (non-CGLIB) superclass implement BeanFactoryAware?// If so, call its setBeanFactory() method. If not, just exit.// 如果实现了BeanFactoryAware,则调用setBeanFactory()方法if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {return proxy.invokeSuper(obj, args);}return null;}// 匹配的是setBeanFactory方法@Overridepublic boolean isMatch(Method candidateMethod) {return isSetBeanFactory(candidateMethod);}public static boolean isSetBeanFactory(Method candidateMethod) {return (candidateMethod.getName().equals("setBeanFactory") &&candidateMethod.getParameterCount() == 1 &&BeanFactory.class == candidateMethod.getParameterTypes()[0] &&BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));}
}

谨防入坑

FactoryBean注入进Spring后,其BeanName真的是&FactoryBean吗?

首先声明:不是;他只是Spring在代码中判断Bean是否为FactoryBean的一个标记,并不是注入进Spring后其BeanName加了&;

上实验截图:

我们发现,在beanDefinition中查询getMyFactoryBean,发现其指向的仍然是MyBeanConfig.class#getMyFactoryBean();

那么我们看下单例池中的数据:

可以发现,其实在单例池中BeanName=getMyFactoryBean,其Value=MyFactoryBean对象,而不是MyBean对象;那MyBean对象是在哪里存储的呢?请看下一个问题。

因此,我们发现Spring的bd集合和单例池中,不存在FactoryBean注入进去后其BeanName加了"&"号。

FactoryBean中getObject()对象什么时候注入进Spring中的?

从前面的分析看出来,程序已经执行完了,但bd和单例池中都没有MyBean对象,那么FactoryBean的getObject()对象什么时候被调用的呢?

其实,当我们调用完applicationContext.refresh();后,我们会把扫描的,手动注册的bd去实例化对应的Bean放入单例池中,而我们并没有特殊处理FactoryBean.getObject()方法,所以我们的bd中是没有FactoryBean.getObject()对应的bd的,因此单例池中也不会有相应的实例化对象;

那当我们调用getBean的时候为什么会拿出MyBean对象呢?

Object getMyFactoryBean = applicationContext.getBean("getMyFactoryBean");

这时,doGetBean()会将其MyFactoryBean的实例化对象取出来,如果MyFactoryBean不是FactoryBean就将其返回,若是FactoryBean,就会调用其getObject()方法将MyBean对象创建出来,然后返回。因此getMyFactoryBean返回的是MyBean对象;

那么如果我们调用两次getBean呢?

Object getMyFactoryBean = applicationContext.getBean("getMyFactoryBean");
Object getMyFactoryBean1 = applicationContext.getBean("getMyFactoryBean");

这时返回的getMyFactoryBean和getMyFactoryBean1是同一个MyBean对象。我们会疑问,MyBean对象并没有放入beanFactory的单例池中,那么第二次调用getBean()返回的对象是存储在哪里的呢?

原来,我们的beanFactory继承了FactoryBeanRegistrySupport.class类,它其中有个factoryBeanObjectCache专门存储factoryBean创建的对象,因此,第二次调用不会再次调用getObject()方法,而是从缓存中直接取。

private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap(16);

总结:factoryBean.getObject()方法最终调用是在getBean()的时候,并且有个factoryBeanObjectCacheMap去保存对象,不存放在单例池中;

如果@Configuration被换成了@Component,@Bean方法还会生成单例吗?

答案:不会!

都没有CGLIB代理了,肯定不会是单例,每次调用都会生成新的对象。

Spring源码|解析深入Spring源码多图剖析@Configuration背后的BeanFactory后置处理器实现逻辑相关推荐

  1. Spring容器创建流程(4)调用beanFactory后置处理器

    postProcessBeanFactory() 方法留给子类去实现. invokeBeanFactoryPostProcessors() 调用bean工厂的后置处理器(以前的执行流程可在系列文章中查 ...

  2. Spring学习笔记八--Bean生命周期和后置处理器

    为什么80%的码农都做不了架构师?>>>    Bean生命周期和后置处理器 IOC容器的bean生命周期 1.构造器或工厂方法建立bean实例 2.bean属性赋值,引用其他bea ...

  3. spring 源码深度解析_spring源码解析之SpringIOC源码解析(下)

    前言:本篇文章接SpringIOC源码解析(上),上一篇文章介绍了使用XML的方式启动Spring,介绍了refresh 方法中的一些方法基本作用,但是并没有展开具体分析.今天就和大家一起撸一下ref ...

  4. 源码解析:Spring源码解析笔记(五)接口设计总览

    本文由colodoo(纸伞)整理 QQ 425343603 Java学习交流群(717726984) Spring解析笔记 启动过程部分已经完成,对启动过程源码有兴趣的朋友可以作为参考文章. 源码解析 ...

  5. 人人都能看懂的Spring源码解析,Spring如何解决循环依赖

    人人都能看懂的Spring源码解析,Spring如何解决循环依赖 原理解析 什么是循环依赖 循环依赖会有什么问题? 如何解决循环依赖 问题的根本原因 如何解决 为什么需要三级缓存? Spring的三级 ...

  6. Spring源码篇一之beanFactory的真身和6大后置处理器的注册

    当你的才华还撑不起你的野心的时候,唯有静下心来学习. spring运行流程图(https://www.processon.com/view/5f3fcab8e0b34d07118258cb?fromn ...

  7. spring源码:九大后置处理器

    目的: spring在完成一个bean的初始化.实例化的过程中,会用到九个后置处理器:本文梳理出这九个后置处理器 九大后置处理器 spring在初始化的过程中,会在九个地方分别调用了五个后置处理的九个 ...

  8. Spring中BeanPostProcessors后置处理器到底在哪里拦截

    研究spring源码的时候,发现注入bean到spring对象中有很多种,有一种是@bean注解,并且括号里可以写一些初始化时要执行的方法,还有销毁时执行的方法,spring中后置处理器可以将某些be ...

  9. Spring的9处调用后置处理器

    在Sping的整个生命周期中,有9个地方调用后置处理器.这些后置处理器是spring实现自定义功能或者扩展spring的核心所在 一.实例化前 该方法属于InstantiationAwareBeanP ...

最新文章

  1. 随机产生长度为20的字符串(数字和大小写字母)
  2. idea无法找到主启动类_idea 启动springboot项目报找不到主类
  3. go 原子操作 atomic
  4. Visual C++ 2008 runtime files are out of data
  5. bzoj 2821:作诗 分块
  6. python难学吗-我没有基础,能否学会Python?Python难吗?
  7. 列车座位应考虑向后摆放
  8. 几款好用的录屏软件推荐
  9. HEU KMS ActivatorV7.8.6迷你版 激活工具使用
  10. vba 冻结窗格_在VBA中进行调试-2A)代码窗格(F7)
  11. 新唐M480系列单片机写入dataflash数据
  12. Access2007实用教程pdf
  13. Livy:基于Apache Spark的REST服务
  14. 无胁科技-TVD每日漏洞情报-2022-11-16
  15. lnmp环境thinkphp配置
  16. 【编程方法】如何阅读开源代码
  17. dedecms织梦模板网站如何进行安全设置 防黑加固
  18. 4G EPS 中的 PLMN 选择
  19. 故障案例----tokudb启动失败
  20. vgg16卷积层的计算量_卷积神经网络VGG16参数数量的计算和理解

热门文章

  1. 20款前端特效动画及源码
  2. linux大型网络游戏,两款大型的Linux下的网络游戏
  3. 【vscode】网易云音乐插件Please interact with the document first otherwise play() will failed解决方法
  4. 10.【CSS定位】:position、z-index、dispaly(none)、visibility、overflow hot new 模块 + 淘宝焦点图布局 +土豆网鼠标经过显示遮罩
  5. 安卓手机小说阅读器_小说迷安卓app2020最新版下载安卓版下载_小说迷安卓app2020最新版下载v3.1.8手机版apk下载...
  6. 我去,神操作!虚拟机Ubuntu18.04居然可以安装NVIDIA + 附带安装源码与命令
  7. 【自动驾驶】高精地图在无人驾驶中的应用
  8. java aria,ARIA 标签和关系
  9. iCloud Drive,简单实用的苹果原生云存储
  10. 基于ESO的永磁同步电机无感FOC 采用线性扩张状态观测器(LESO)估计电机反电势,利用锁相环从反电势中提取位置和转速信息