4.Dubbo源码分析----Reference标签的处理

 前面对于Service标签的处理已经说明了Dubbo源码分析----Dubbo的Service注解分析
,现在对Reference标签的处理进行解释。
 对于Reference标签的解析还是按照前面的分析找到ReferenceAnnotationBeanPostProcessor类这个类是dubbo中AnnotationInjectedBeanPostProcessor的子类,而AnnotationInjectedBeanPostProcessor类又继承了spring的AnnotationInjectedBeanPostProcessor类同时实现了MergedBeanDefinitionPostProcessor类。

类图

 其中AnnotationInjectedBeanPostProcessor重载了postProcessPropertyValues跟postProcessMergedBeanDefinition方法,对于这两个方法先进行说明。

  • postProcessPropertyValues:这个方法是InstantiationAwareBeanPostProcessor接口中定义的,作用是对实例化之后属性设置之前Bean 的属性值进行修改。调用这个方法的前提是postProcessAfterInstantiation方法返回true,其中postProcessAfterInstantiation方法在InstantiationAwareBeanPostProcessorAdapter默认返回是true。
  • postProcessMergedBeanDefinition:这个方法是在MergedBeanDefinitionPostProcessor类中定义的,作用是在Bean合并之后回调用,也就是Bean属性填充完毕之后。

    所以按顺序,现在先进入到postProcessPropertyValues方法中。
    @Override
    public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
        //获取注入用的元数据
        InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
        try {
            //进行注入
            metadata.inject(bean, beanName, pvs);
        } catch (BeanCreationException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getName()
                    + " dependencies is failed", ex);
        }
        return pvs;
    }

postProcessPropertyValues方法主要是对Bean中的属性的获取,其中InjectionMetadata对象是spring中用于管理注入元数据的内部类。现在进入findInjectionMetadata方法

    private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
        //生成缓存的cacheKey
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        //检查对应的用于诸如用的元数据是否存在缓存
        AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
        //如果元数据是空的,或者元数据缓存中保存的Class对象不是传入的Class对象
        if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            synchronized (this.injectionMetadataCache) {
                metadata = this.injectionMetadataCache.get(cacheKey);
                //双重检查锁
                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                    //如果元数据不是null就对其中的属性进行清空
                    if (metadata != null) {
                        metadata.clear(pvs);
                    }
                    try {
                        //创建元数据
                        metadata = buildAnnotatedMetadata(clazz);
                        //放到缓存中进行保存
                        this.injectionMetadataCache.put(cacheKey, metadata);
                    } catch (NoClassDefFoundError err) {
                        throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
                                "] for annotation metadata: could not find class that it depends on", err);
                    }
                }
            }
        }
        return metadata;
    }

上面的逻辑也比较简单,就是先检查缓存和比较Class对象判断是不是同一个,如果缓存为空或者缓存的Class对象不是传入的Class对象,就需要先进行缓存的清楚然后创建InjectionMetadata进行保存。现在对元数据的创建进行解析

    private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
        //获取AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement
        Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
        //获取AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement
        Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
        //上面的两个集合中的对象都是spring中InjectionMetadata类的内部类InjectedElement的继承类用来保存单个元素
        return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);

    }
    
//-------------

        private List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {

        final List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement>();
        // 通过反射的工具类,获取当前beanClass中的所有Field,然后通过实现ReflectionUtils类的内部类FieldCallback的实现,来对字段进行处理
        ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
            @Override
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                //获取field里面的Reference标签
                A annotation = getAnnotation(field, getAnnotationType());
                //检查标签是不是null
                if (annotation != null) {
                    //field不是static类型的
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("@" + getAnnotationType().getName() + " is not supported on static fields: " + field);
                        }
                        return;
                    }
                    //创建AnnotatedFieldElement并放到集合中
                    elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement(field, annotation));
                }

            }
        });
        return elements;
    }
//--------------------
    private List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {

        final List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement>();
        //获取到beanClass中所有的Method,然后调用实现的ReflectionUtils.MethodCallback类的doWith方法
        ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
            @Override
            public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                //寻找method的桥接方法,关于桥接方法这是在Java1.5引入泛型之后,编译器为了向前兼容,生成这个的
                Method bridgedMethod = findBridgedMethod(method);
                //检查是不是可见的桥接方法
                if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                //找到方法上的Reference标签
                A annotation = findAnnotation(bridgedMethod, getAnnotationType());
                //如果标签不是bull并且找到beanClass中的具体的方法
                if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
                    //方法不能是静态的
                    if (Modifier.isStatic(method.getModifiers())) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("@" + getAnnotationType().getSimpleName() + " annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    //需要有参数
                    if (method.getParameterTypes().length == 0) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("@" + getAnnotationType().getSimpleName() + " annotation should only be used on methods with parameters: " +
                                    method);
                        }
                    }
                    //获取beanClass中指定方法的属性
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
                    elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement(method, pd, annotation));
                }
            }
        });
        return elements;
    }

 上面分析了从传入的Bean中获取对应的元数据后保存到InjectionMetadata对象中,现在就是进行注入了。inject方法也是一个模板方法,首先调用的InjectionMetadata的inject然后调用AnnotationInjectedBeanPostProcessor类中的内部类实现的inject方法。

//InjectionMetadata中的inject
    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        Collection<InjectedElement> checkedElements = this.checkedElements;
        //如果checkedElements为空就使用传入的injectedElements,这里传入的是fieldElements, methodElements两个的组合
        Collection<InjectedElement> elementsToIterate =
                (checkedElements != null ? checkedElements : this.injectedElements);
        if (!elementsToIterate.isEmpty()) {
            //迭代然后调用实现的inject方法
            for (InjectedElement element : elementsToIterate) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Processing injected element of bean '" + beanName + "': " + element);
                }
                element.inject(target, beanName, pvs);
            }
        }
    }
//-----------------------内部类AnnotatedFieldElement跟AnnotatedMethodElement中的方法
    protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
        //获取类型
        Class<?> injectedType = field.getType();
        //获取注入之后的对象
        Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this);
        //如果是私有字段先设置makeAccessible属性
        ReflectionUtils.makeAccessible(field);
        //给Bean对象设置诸如之后的对象
        field.set(bean, injectedObject);
    }
//------getInjectedObject方法
    protected Object getInjectedObject(A annotation, Object bean, String beanName, Class<?> injectedType,
                                       InjectionMetadata.InjectedElement injectedElement) throws Exception {
        //构建缓存对的key
        String cacheKey = buildInjectedObjectCacheKey(annotation, bean, beanName, injectedType, injectedElement);
        //先查询缓存
        Object injectedObject = injectedObjectsCache.get(cacheKey);
        //缓存为null
        if (injectedObject == null) {
            //创建注入之后的对象
            injectedObject = doGetInjectedBean(annotation, bean, beanName, injectedType, injectedElement);
            // Customized inject-object if necessary
            injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
        }
        return injectedObject;
    }
//------doGetInjectedBean方法
    protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
                                       InjectionMetadata.InjectedElement injectedElement) throws Exception {
        //创建应用Bean 的name,根据接口的名称,类型,group等拼接进行闯进
        String referencedBeanName = buildReferencedBeanName(reference, injectedType);
        //如果不存在则创建ReferenceBean对象
        ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
        //保存到缓存中
        cacheInjectedReferenceBean(referenceBean, injectedElement);
        //创建reference的代理类
        Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);
        //返回
        return proxy;
    }

上面就就是对@Reference标签的处理过程,根据获取到的元数据,最后创建一个贴有@Reference标签的接口的代理类。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 1 我们常常对此处的美浑然不知,而永不满足地继续追寻新的别处。 朋友A最近经历了事业的低谷,跟单位行政发生了一些矛...
    徴5羽6阅读 577评论 1 3
  • 晚上做了一个长长的梦,醒来发现枕头已经湿了。 梦里B他长得不是非常好看帅气,只能算清秀比一般人好点。他是一个公司的...
    bear的树洞阅读 221评论 0 3
  • 温佳一如既往地紧张而忙碌着。还好,有惠特博士的指导和协助下,新项目的研发进度一切顺利。由于公司离家比较远,温佳习惯...
    9443cd77422a阅读 401评论 0 0
  • 前段时间,妈妈给我再励智学校报了英语班。 第一天上课,...
    布伊文阅读 506评论 0 0
  • 很奇怪,有的人你明明用心去对待,却怎么都换不来她的热情相拥。虽然足够熟悉和亲密,但你却从来都不是她最记挂的人。似...
    光合故事阅读 170评论 0 2