spring源碼------@Configuration跟@Component及其派生注解@Service等的區(qū)別以及spring對(duì)其代理增強(qiáng)的原理

@[TOC]

1.常用的注解婚度,以及@Configuration的特殊性

?Spring中提供了很多將對(duì)象注入到容器中的注解秸仙,這里將這些注解列舉出來(lái)飞蚓。@Component踱稍,@Indexed弟跑,@Controller灾前,@Repository@Service孟辑,@Configuration哎甲。另外還有一個(gè)需要跟@Configuration蔫敲,@Component以及派生注解一起使用的注解@Bean
?雖然我們經(jīng)常使用這些注解中的炭玫,但是其實(shí)@Configuration跟其他的注解有點(diǎn)不一樣奈嘿,這個(gè)注解在默認(rèn)情況下Spring會(huì)通過(guò)CGLIB的方式對(duì)貼有這個(gè)注解的對(duì)象進(jìn)行增強(qiáng)。而這個(gè)決定是否進(jìn)行增強(qiáng)的關(guān)鍵吞加,在于@Configuration注解中的proxyBeanMethods屬性裙犹。當(dāng)這個(gè)屬性為true的時(shí)候會(huì)進(jìn)行增強(qiáng),而默認(rèn)情況這個(gè)屬性值就是true衔憨。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor(annotation = Component.class)
    String value() default "";
    
    boolean proxyBeanMethods() default true;
}

&esmp;從上面其實(shí)能看到@Configuration注解本身也是@Component注解的一個(gè)派生注解叶圃,但是為什么Spring會(huì)對(duì)其進(jìn)行增強(qiáng)呢,接下來(lái)進(jìn)行分析践图。

2. @Configuration特殊性的源碼解析

2.1 貼有@Configuration的bean的獲取

?spring對(duì)于@Configuration注解的解析掺冠,跟@Conditional注解的解析大部分過(guò)程一樣都是在ConfigurationClassPostProcessor中進(jìn)行的,可以通過(guò)@Conditional注解解析的文章看看前面的過(guò)程码党。Spring擴(kuò)展------基于@Conditional注解以及Condition接口的擴(kuò)展
德崭。這里天過(guò)前面的步驟,直接進(jìn)入到此類中進(jìn)行分析闽瓢。

2.1.1 bean注冊(cè)前進(jìn)行分類的方法checkConfigurationClassCandidate

?在這個(gè)類中有一個(gè)方法checkConfigurationClassCandidate用來(lái)檢查當(dāng)前注冊(cè)的類是不是候選configuration class也就是需要進(jìn)行代理的類接癌。這個(gè)方法的調(diào)用的位置都是在,將對(duì)應(yīng)的候選bean放入到需要注冊(cè)的候選bean的集合這個(gè)步驟前扣讼。這個(gè)貼代碼看看

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    ......
    for (String beanName : candidateNames) {
            //獲取對(duì)應(yīng)的BeanDefinition
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
            //檢查BeanDefinition是不是Configuration類型的候選bean缺猛,
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }
    ......
        //檢查BeanDefinition是不是Configuration類型的候選bean,并且這沒(méi)有被解析過(guò)
        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
        }
        ......              
}

?可以看到在將候選bean放入到需要注冊(cè)的候選bean集合之前都會(huì)對(duì)bean進(jìn)行的檢查椭符,這也可以看成是一個(gè)過(guò)濾 的過(guò)程荔燎,將那些需要進(jìn)行代理的bean進(jìn)行分類。分類的過(guò)程就在checkConfigurationClassCandidate方法中销钝。這個(gè)方法在ConfigurationClassUtils類中有咨,現(xiàn)在看看這個(gè)方法的主要步驟

    public static boolean checkConfigurationClassCandidate(
            BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
        ......
        //獲取源數(shù)據(jù)中包含Configuration注解的信息
        Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
        //如果存在Configuration注解,并且proxyBeanMethods是true蒸健,則表示需要進(jìn)行代理
        if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        }
        //如果存在Configuration注解座享,但是proxyBeanMethods是false,則表示不需要進(jìn)行代理
        //如果不存在Configuration注解似忧,但是如果bean中包含Component渣叛,ComponentScan,Import盯捌,ImportResource或者Bean注解淳衙,則也不需要代理,但是是候選bean
        else if (config != null || isConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        }
        //如果滿足上面判斷條件則表示不是候選bean
        else {
            return false;
        }
        ......
    }

?這里做的就是獲取傳進(jìn)來(lái)的候選bean上面的@Configuration注解,然后進(jìn)行判斷箫攀,主要有以下幾種判斷肠牲。

貼有@Configuration注解 @Configuration注解的proxyBeanMethodstrue 是否需要代理
滿足 滿足 需要
滿足 不滿足 不需要
不滿足 - 不需要

?上面滿足條件需要代理的bean,會(huì)在封裝其信息的BeanDefinition對(duì)象中加上一個(gè)屬性CONFIGURATION_CLASS_ATTRIBUTE值為CONFIGURATION_CLASS_FULL靴跛。這里需要注意這個(gè)屬性有兩種值缀雳,需要進(jìn)行區(qū)分。

說(shuō)明 情況
CONFIGURATION_CLASS_FULL 需要對(duì)bean進(jìn)行代理 貼有@Configuration注解的對(duì)象的內(nèi)部所有的注入到容器的對(duì)象(貼有@Bean注解的對(duì)象)
CONFIGURATION_CLASS_LITE 不需要對(duì)bean進(jìn)行代理 沒(méi)有貼有@Configuration注解的對(duì)象汤求,即使內(nèi)部存在注入到容器的對(duì)象

?在上面將bean進(jìn)行分類之后俏险,后面就是對(duì)bean進(jìn)行代理增強(qiáng)的階段了。對(duì)bean進(jìn)行代理增強(qiáng)的過(guò)程的起始調(diào)用也是在ConfigurationClassPostProcessor類中扬绪。

2.2 對(duì)bean進(jìn)行增強(qiáng)
2.2.1 獲取需要代理增強(qiáng)的bean

?增強(qiáng)的初始過(guò)程在ConfigurationClassPostProcessor類的enhanceConfigurationClasses方法中。這個(gè)方法的調(diào)用在spring上下文初始化之后會(huì)調(diào)用裤唠。

    public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
        Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            //從容器中獲取BeanDefinition
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            //獲取BeanDefinition中的CONFIGURATION_CLASS_ATTRIBUTE屬性
            Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
            MethodMetadata methodMetadata = null;
            if (beanDef instanceof AnnotatedBeanDefinition) {
                methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
            }
            //從加載了@Configuration注解的BeanDefinition的beanClassLoader中獲取對(duì)應(yīng)的beanClass挤牛,因?yàn)槭沁@個(gè)類加載的@Configuration注解的BeanDefinition
            if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
                // Configuration class (full or lite) or a configuration-derived @Bean method
                // -> resolve bean class at this point...
                AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
                if (!abd.hasBeanClass()) {
                    try {
                        //從beanClassLoader中獲取到真正加載的bean的Classes對(duì)象
                        abd.resolveBeanClass(this.beanClassLoader);
                    }
                    catch (Throwable ex) {
                        throw new IllegalStateException(
                                "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                    }
                }
            }
            //如果CONFIGURATION_CLASS_ATTRIBUTE屬性是CONFIGURATION_CLASS_FULL
            if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
                if (!(beanDef instanceof AbstractBeanDefinition)) {
                    throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                            beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
                }
                //如果是AbstractBeanDefinition類型的BeanDefinition需要檢查這個(gè)bean是不是已經(jīng)被實(shí)例化了,如果是的則不能進(jìn)行代理
                else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                    logger.info("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'.");
                }
                //放到需要進(jìn)行代理的對(duì)象中
                configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
            }
        }
        if (configBeanDefs.isEmpty()) {
            // nothing to enhance -> return immediately
            return;
        }
        ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
        for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
            //獲取AbstractBeanDefinition
            AbstractBeanDefinition beanDef = entry.getValue();
            // If a @Configuration class gets proxied, always proxy the target class
            //如果一個(gè)bean已經(jīng)代理過(guò)了种蘸,則設(shè)置這個(gè)狀態(tài)未true
            beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
            // Set enhanced subclass of the user-specified bean class
            //進(jìn)行代理
            Class<?> configClass = beanDef.getBeanClass();
            Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
            if (configClass != enhancedClass) {
                if (logger.isTraceEnabled()) {
                    logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                            "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
                }
                beanDef.setBeanClass(enhancedClass);
            }
        }
    }

?總結(jié)以下上面的步驟:

  1. 從當(dāng)前的容器中獲取所有的需要注冊(cè)的bean集合墓赴,然后循環(huán)開(kāi)始2-3步驟,直到結(jié)束
  2. 獲取BeanDefinition中的CONFIGURATION_CLASS_ATTRIBUTE屬性航瞭,然后獲取需要代理的bean的真實(shí)的Class對(duì)象
  3. 檢查CONFIGURATION_CLASS_ATTRIBUTE屬性是不是CONFIGURATION_CLASS_FULL诫硕,不是則跳過(guò)進(jìn)入下一個(gè)bean然后到步驟2。是的則將bean放到需要代理的bean的集合中刊侯,然后進(jìn)入2步驟
  4. 迭代需要代理的bean的集合進(jìn)行代理增強(qiáng)章办。
2.2.2 對(duì)bean進(jìn)行代理增強(qiáng)

&esmp;代理增強(qiáng)的邏輯在ConfigurationClassEnhancer類的enhance方法中。

    public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
        //如果當(dāng)前的configClass已經(jīng)是EnhancedConfiguration的子類滨彻,說(shuō)明這個(gè)類已經(jīng)被代理了藕届,因?yàn)楹竺娲淼念悤?huì)設(shè)置接口是EnhancedConfiguration
        if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
            if (logger.isDebugEnabled()) {
                logger.debug(String.format("Ignoring request to enhance %s as it has " +
                        "already been enhanced. This usually indicates that more than one " +
                        "ConfigurationClassPostProcessor has been registered (e.g. via " +
                        "<context:annotation-config>). This is harmless, but you may " +
                        "want check your configuration and remove one CCPP if possible",
                        configClass.getName()));
            }
            return configClass;
        }
        //創(chuàng)建一個(gè)Enhancer然后進(jìn)行代理
        Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
        if (logger.isTraceEnabled()) {
            logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
                    configClass.getName(), enhancedClass.getName()));
        }
        //返回代理類
        return enhancedClass;
    }

?可以看到上面的就是用CGILB進(jìn)行代理的,在其創(chuàng)建Enhancer的時(shí)候亭饵,會(huì)設(shè)置一些參數(shù)休偶,這些參數(shù)就是用來(lái)與普通的CGLIB進(jìn)行區(qū)分的。

    private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
        Enhancer enhancer = new Enhancer();
        //設(shè)置父類或者接口類為需要代理的目標(biāo)類
        enhancer.setSuperclass(configSuperClass);
        //設(shè)置實(shí)現(xiàn)的接口EnhancedConfiguration
        enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
        //是否需要實(shí)現(xiàn)Factory接口
        enhancer.setUseFactory(false);
        //設(shè)置命名規(guī)則為了避免Spring的CGLIB版本與常規(guī)的CGLIB之間的沖突
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        //設(shè)置生成策略
        enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
        //設(shè)置回調(diào)
        enhancer.setCallbackFilter(CALLBACK_FILTER);
        //設(shè)置回調(diào)類型
        enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
        return enhancer;
    }

?在這里需要關(guān)注一下setCallbackFilter這個(gè)方法設(shè)置的CALLBACK_FILTER辜羊。CALLBACK_FILTER是一個(gè)對(duì)象的數(shù)組踏兜。

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

    private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);

?這里包含四個(gè)類BeanMethodInterceptorBeanFactoryAwareMethodInterceptor八秃,NoOp的空實(shí)現(xiàn)類SerializableNoOp碱妆,ConditionalCallbackFilter,其中第三個(gè)NoOp在spring中是空實(shí)現(xiàn)不用管喜德。主要看ConditionalCallbackFilter山橄,BeanFactoryAwareMethodInterceptorBeanMethodInterceptor這三個(gè)類。

2.2.3 方法回調(diào)的過(guò)濾處理ConditionalCallbackFilter

?CallbackFilter在CGLIB 中起到回調(diào)的作用,就是一個(gè)方法的執(zhí)行時(shí)候的攔截過(guò)濾的作用航棱。spring實(shí)現(xiàn)了自己的ConditionalCallbackFilter睡雇。在這個(gè)里面會(huì)對(duì)方法進(jìn)行過(guò)濾。

    private static class ConditionalCallbackFilter implements CallbackFilter {

        private final Callback[] callbacks;

        private final Class<?>[] callbackTypes;

        public ConditionalCallbackFilter(Callback[] callbacks) {
            //設(shè)置Callback饮醇,這里就是BeanMethodInterceptor, BeanFactoryAwareMethodInterceptor, NoOp的空實(shí)現(xiàn)類SerializableNoOp這三個(gè)類
            this.callbacks = callbacks;
            this.callbackTypes = new Class<?>[callbacks.length];
            for (int i = 0; i < callbacks.length; i++) {
                this.callbackTypes[i] = callbacks[i].getClass();
            }
        }

        @Override
        public int accept(Method method) {
            //進(jìn)行循環(huán)處理
            for (int i = 0; i < this.callbacks.length; i++) {
                Callback callback = this.callbacks[i];
                //如果是ConditionalCallback的實(shí)現(xiàn)類它抱,并且isMatch方法通過(guò)則返回對(duì)應(yīng)的callback所在的順序
                if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
                    return i;
                }
            }
            throw new IllegalStateException("No callback available for method " + method.getName());
        }

?可以看到這里最主要的作用就是設(shè)置自己的Callback,也就是BeanMethodInterceptor朴艰,BeanFactoryAwareMethodInterceptor观蓄,NoOp。然后進(jìn)行過(guò)濾這些Callback祠墅,其中ConditionalCallback也是ConfigurationClassEnhancer類的內(nèi)部類侮穿。只定義了一個(gè)方法isMatch,作用是檢查對(duì)應(yīng)的攔截方法是否需要進(jìn)行攔截毁嗦。

    private interface ConditionalCallback extends Callback {

        boolean isMatch(Method candidateMethod);
    }

?其中isMatch方法由BeanFactoryAwareMethodInterceptorBeanMethodInterceptor實(shí)現(xiàn)亲茅。接下來(lái)就是這兩個(gè)類

2.2.4 將容器設(shè)置到代理對(duì)象中的BeanFactoryAwareGeneratorStrategy

?BeanFactoryAwareGeneratorStrategy實(shí)現(xiàn)了CGLIB的DefaultGeneratorStrategy用來(lái)在生成代理對(duì)象的時(shí)候,設(shè)置額外的信息到代理對(duì)象中狗准。也是在這里將克锣,容器對(duì)象BeanFactory放到了代理對(duì)象中,這里只截取部分的代碼腔长。

    private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy {
        ......
        @Override
        protected ClassGenerator transform(ClassGenerator cg) throws Exception {
            //實(shí)現(xiàn)ClassEmitterTransformer袭祟,為代理對(duì)象增加額外的字段BEAN_FACTORY_FIELD,訪問(wèn)級(jí)別是PUBLIC捞附,類型為BeanFactory
            ClassEmitterTransformer transformer = new ClassEmitterTransformer() {
                @Override
                public void end_class() {
                    declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
                    super.end_class();
                }
            };
            return new TransformingClassGenerator(cg, transformer);
        }
        ......
    }

?設(shè)置的這個(gè)值巾乳,在后面的兩個(gè)攔截其中都會(huì)用到

2.2.5 增加容器到代理對(duì)象中的BeanFactoryAwareMethodInterceptor

?BeanFactoryAwareMethodInterceptor主要用來(lái)處理實(shí)現(xiàn)了BeanFactoryAware類的setBeanFactory方法類。

    private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {

        @Override
        @Nullable
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            //從代理的對(duì)象中獲取BEAN_FACTORY_FIELD字段
            Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
            Assert.state(field != null, "Unable to find generated BeanFactory field");
            //將BEAN_FACTORY_FIELD字段設(shè)置到obj對(duì)象中
            field.set(obj, args[0]);

            //如果當(dāng)前代理類的父類實(shí)現(xiàn)了BeanFactoryAware故俐,則調(diào)用setBeanFactory方法想鹰,如果不是就推出
            if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
                return proxy.invokeSuper(obj, args);
            }
            return null;
        }

        @Override
        public boolean isMatch(Method candidateMethod) {
            //檢查是否是設(shè)置BeanFactory的方法
            return isSetBeanFactory(candidateMethod);
        }

        public static boolean isSetBeanFactory(Method candidateMethod) {
            //方法名是setBeanFactory,參數(shù)個(gè)數(shù)為1個(gè)药版,平且參數(shù)類型是BeanFactory類型辑舷,方法是BeanFactoryAware的實(shí)現(xiàn)類
            return (candidateMethod.getName().equals("setBeanFactory") &&
                    candidateMethod.getParameterCount() == 1 &&
                    BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
                    BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
        }
    }
2.2.6 處理@Configuration注解中@Bean注解的BeanMethodInterceptor

?BeanMethodInterceptor主要處理@Configuration注解中貼有@Bean注解的方法。也正是這個(gè)方法槽片,讓@Configuration有了區(qū)別于@Component注解中貼有@Bean注解的方法的原因之一何缓。主要邏輯集中在這個(gè)類的
intercept方法中,現(xiàn)在來(lái)看看:
?這里要先看看實(shí)現(xiàn)了ConditionalCallback接口的isMatch方法还栓,因?yàn)檫@個(gè)會(huì)先被調(diào)用

        public boolean isMatch(Method candidateMethod) {
            //定義當(dāng)前方法的對(duì)象不是Object碌廓,并且不是方法不是setBeanFactory方法,并且方法上面包含@Bean注解
            return (candidateMethod.getDeclaringClass() != Object.class &&
                    !BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
                    BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
        }

?到這里就知道剩盒,只要是聲明方法的類Object類谷婆,方法名不是setBeanFactory貼了@Bean注解就會(huì)被攔截。
?接下來(lái)就是攔截之后的處理邏輯了。

        public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
                    MethodProxy cglibMethodProxy) throws Throwable {
            //從代理的實(shí)例中獲取beanFactory纪挎,根據(jù)BEAN_FACTORY_FIELD字段獲取期贫,而這個(gè)字段在enhanced對(duì)象創(chuàng)建設(shè)置stratege的BeanFactoryAwareGeneratorStrategy類中設(shè)置的
            ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
            //獲取到方法上@Bean注解的name屬性或者方法名來(lái)決定bean的名稱
            String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
            // Determine whether this bean is a scoped-proxy
            //檢查緩存中是否有方法的@Scope注解信息緩存,如果沒(méi)有則檢查是否有@Scope注解并且proxyMode不是NO
            if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
                //生成作用域代理內(nèi)用于引用目標(biāo)bean的bean名稱
                String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
                if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
                    beanName = scopedBeanName;
                }
            }

            /**
             * 為了處理bean間方法引用的情況异袄,我們必須顯式地檢查容器中已經(jīng)緩存的實(shí)例通砍。
             * 檢查當(dāng)前的bean是不是一個(gè)FactoryBean,如果是這樣創(chuàng)建一個(gè)子類roxy烤蜕,攔截對(duì)getObject()的調(diào)用并返回所有緩存的bean實(shí)例
             * 這確保了從@Bean方法中調(diào)用FactoryBean的語(yǔ)義與在XML中引用FactoryBean的語(yǔ)義相同
             */
            if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
                    factoryContainsBean(beanFactory, beanName)) {
                Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
                if (factoryBean instanceof ScopedProxyFactoryBean) {
                    //作用域代理工廠bean是一種特殊情況封孙,不應(yīng)該進(jìn)一步代理
                    // Scoped proxy factory beans are a special case and should not be further proxied
                }
                else {
                    // It is a candidate FactoryBean - go ahead with enhancement
                    //進(jìn)行增強(qiáng)
                    return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
                }
            }
            //檢查當(dāng)前的方法是不是當(dāng)前調(diào)用的工廠方法,就是當(dāng)前攔截的方法是不是當(dāng)前貼有@Configuration注解類里面貼有@Bean注解的方法
            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.
                //工廠調(diào)用bean方法是為了實(shí)例化和注冊(cè)bean(即通過(guò)getBean()調(diào)用)->調(diào)用父類方法來(lái)實(shí)際創(chuàng)建bean實(shí)例讽营。
                if (logger.isInfoEnabled() &&
                        BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
                    logger.info(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()));
                }
                //調(diào)用父類方法
                return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
            }
            //從容器獲取bean
            return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
        }

?這里需要說(shuō)明的以下幾點(diǎn)

  1. BeanMethodInterceptorConfigurationClassEnhancer的一個(gè)內(nèi)部類
    enhancedConfigInstance對(duì)象中的
  2. 當(dāng)貼有@Bean注解的方法返回的是BeanFactory的子類的時(shí)候虎忌,會(huì)先獲取到實(shí)際的bean,也就是beanName前面加上“&”符號(hào)橱鹏,然后進(jìn)行代理
  3. isCurrentlyInvokedFactoryMethod用來(lái)驗(yàn)證當(dāng)前攔截的方法是不是貼有@Bean注解的方法呐籽,是的話會(huì)調(diào)用代理的方法。如果不是則直接從容器中獲取bean蚀瘸。
3.@Configuration@Component例證

如果在@Configuration注解的類的中有@Bean注解在方法上來(lái)注入對(duì)象,當(dāng)調(diào)用這個(gè)方法的時(shí)候庶橱,返回的是容器里面已經(jīng)創(chuàng)建好的對(duì)象贮勃。舉個(gè)例子

@Configuration
public class ConfigurationTest {
    @Bean
    public BeanB beanB(){
        BeanB beanB = new BeanB();
        System.out.println("beanB one---"+beanB);
        return beanB;
    }

    @Bean
    @DependsOn(value = "beanB")
    public BeanA beanA(){
        System.out.println("beanA");
        BeanA beanA = new BeanA();
        beanA.setBeanB(beanB());
        System.out.println("beanB two---"+beanA.getBeanB());
        return beanA;
    }
}

?當(dāng)從容器中獲取beanA的時(shí)候。打印的結(jié)果如下

beanB one---springstudy.configuration.BeanB@2611b9a3
beanA
beanB two---springstudy.configuration.BeanB@2611b9a3

?當(dāng)我們把ConfigurationTest類上面的@Configuration注解換成@Component的時(shí)候苏章,看結(jié)果如下

beanB one---springstudy.configuration.BeanB@6d24ffa1
beanA
beanB one---springstudy.configuration.BeanB@65a4798f
beanB two---springstudy.configuration.BeanB@65a4798f

?發(fā)現(xiàn)會(huì)創(chuàng)建兩次BeanB對(duì)象寂嘉。
?會(huì)發(fā)生這種區(qū)別的原因就是,當(dāng)時(shí)存在@Configuration注解的時(shí)候枫绅,beanBbeanA方法會(huì)被代理增強(qiáng)泉孩,在beanA方法中調(diào)用beanB方法的時(shí)候會(huì)被攔截,并返回容器中已經(jīng)創(chuàng)建的BeanB對(duì)象并淋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末寓搬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子县耽,更是在濱河造成了極大的恐慌句喷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兔毙,死亡現(xiàn)場(chǎng)離奇詭異唾琼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)澎剥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)锡溯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事祭饭∥咭穑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵甜癞,是天一觀的道長(zhǎng)夕晓。 經(jīng)常有香客問(wèn)我,道長(zhǎng)悠咱,這世上最難降的妖魔是什么蒸辆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮析既,結(jié)果婚禮上躬贡,老公的妹妹穿的比我還像新娘。我一直安慰自己眼坏,他們只是感情好拂玻,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著宰译,像睡著了一般檐蚜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沿侈,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天闯第,我揣著相機(jī)與錄音,去河邊找鬼缀拭。 笑死咳短,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛛淋。 我是一名探鬼主播咙好,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼褐荷!你這毒婦竟也來(lái)了勾效?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诚卸,失蹤者是張志新(化名)和其女友劉穎葵第,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體合溺,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卒密,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了棠赛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哮奇。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膛腐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鼎俘,到底是詐尸還是另有隱情哲身,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布贸伐,位于F島的核電站勘天,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捉邢。R本人自食惡果不足惜脯丝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伏伐。 院中可真熱鬧宠进,春花似錦、人聲如沸藐翎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吝镣。三九已至堤器,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間末贾,已是汗流浹背吼旧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留未舟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓掂为,卻偏偏與公主長(zhǎng)得像裕膀,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子勇哗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容