栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

揭秘@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 {
    @Bean
    public MyBean createMyBean() {
        return new MyBean();
    }
    
    @Bean
    public 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 configBeanDefs = new linkedHashMap<>();
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        // 将加了@Configuration的配置类放入configBeanDefs
        if (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 immediately
        return;
    }
    // 定义配置类增强器
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class
        beanDef.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;
    }
    // 设置被代理的类class
    Class enhancedClass = createClass(newEnhancer(configClass, classLoader));
    return enhancedClass;
}
(4)ConfigurationClassEnhancer.newEnhancer()

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

最关键的是他实现了两个回调接口BeanMethodInterceptor.class,BeanFactoryAwareMethodInterceptor.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) {
    // 获取被代理的类class
    Class 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(),因此返回false
    if (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工厂里取,不再重新new
    return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}

Bean案例

拿文章开头的demo来分析。

@Configuration
public MyConfiguration {
    @Bean
    public MyBean createMyBean() {
        return new MyBean();
    }
    
    @Bean
    public 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容器中
    @Bean
    public MyFactoryBean getMyFactoryBean() {
        return new MyFactoryBean();
    }

    @Bean
    public MyFactoryBean getMySameFactoryBean() {
        return getMyFactoryBean();
    }
}
// 定义的FactoryBean
public class MyFactoryBean implements FactoryBean {
    @Override
    public MyBean getObject() throws Exception {
        return new MyBean();
    }

    @Override
    public 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
    @Nullable
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 取出代理类中的$$beanFactory
        Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
        Assert.state(field != null, "Unable to find generated BeanFactory field");
        // 设置$$beanFactory
        field.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方法
    @Override
    public 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 factoryBeanObjectCache = new ConcurrentHashMap(16);

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

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

答案:不会!

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/439917.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号