dubboreference注解_dubbo学习篇1 注解之 @Reference 原理解析-程序员宅基地

技术标签: dubboreference注解  

一. 使用注解

在dubbo springboot 使用时,在需要调用的服务接口上使用 @Reference 即可直接调用远程服务

@Reference(version = "1.0.0",

application = "${dubbo.application.id}")

private HelloService helloService;

比如上述样式 调试发现调用时 helloSevice为一个生产的代理对象如下图:

二.分析原理

@Reference 的行为跟 @Autowired 类似 均实现了自动注入的过程 。

@Reference 的注解处理依赖于 ReferenceAnnotationBeanPostProcessor 类 该类的定义如下:

public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor implements

ApplicationContextAware, ApplicationListener {

/**

* The bean name of {@link ReferenceAnnotationBeanPostProcessor}

*/

public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";

/**

* Cache size

*/

private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);

private final ConcurrentMap> referenceBeanCache =

new ConcurrentHashMap<>(CACHE_SIZE);

private final ConcurrentHashMap localReferenceBeanInvocationHandlerCache =

new ConcurrentHashMap<>(CACHE_SIZE);

private final ConcurrentMap> injectedFieldReferenceBeanCache =

new ConcurrentHashMap<>(CACHE_SIZE);

private final ConcurrentMap> injectedMethodReferenceBeanCache =

new ConcurrentHashMap<>(CACHE_SIZE);

private ApplicationContext applicationContext;

其中 referenceBeanCache缓存了接口对应bean的定义 localReferenceBeanInvocationHandlerCache缓存了接口对应InvocationHandler的定义。

参考 autowired的解析过程 分析首先找到 (2.63定义在当前类 原理一致)

class AnnotationInjectedBeanPostProcessor{

@Override

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class> beanType, String beanName) {

if (beanType != null) {

InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);

metadata.checkConfigMembers(beanDefinition);

}

}

}

执行的时间节点是bean刚刚初始化完 但在属性填充之前, spring会为每个beanDefinition依次调用实现了 MergedBeanDefinitionPostProcessor接口的PostProcessor的改方法(注册过程单独放在spring boot 自动配置章节)

该函数依次处理spring传来的beanClass 并解析class field method尝试找到

private List findFieldReferenceMetadata(Class> beanClass) {

final List elements = new LinkedList();

ReflectionUtils.doWithFields(beanClass, new FieldCallback() {

public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {

Reference reference = (Reference)AnnotationUtils.getAnnotation(field, Reference.class);

if (reference != null) {

if (Modifier.isStatic(field.getModifiers())) {

if (ReferenceAnnotationBeanPostProcessor.this.logger.isWarnEnabled()) {

ReferenceAnnotationBeanPostProcessor.this.logger.warn("@Reference annotation is not supported on static fields: " + field);

}

return;

}

elements.add(ReferenceAnnotationBeanPostProcessor.this.new ReferenceFieldElement(field, reference));

}

}

});

return elements;

}

有这个定义的filed或者method 如果存在的话 就建立类定义中对应field method的缓存。同时加入到beanclass/beanname对应该meta信息的缓存 以便同样的请求过来不在解析。

之后 处理调用该函数

public void checkConfigMembers(RootBeanDefinition beanDefinition) {

Set checkedElements = new LinkedHashSet(this.injectedElements.size());

Iterator var3 = this.injectedElements.iterator();

while(var3.hasNext()) {

InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var3.next();

Member member = element.getMember();

if (!beanDefinition.isExternallyManagedConfigMember(member)) {

beanDefinition.registerExternallyManagedConfigMember(member);

checkedElements.add(element);

if (logger.isDebugEnabled()) {

logger.debug("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);

}

}

}

this.checkedElements = checkedElements;

}

这个函数会将上个函数标注出来需要被注入的域标注为"外部管理",只有被标注为外部管理的成员 在后续才会在当前bean实例化调用postProcessPropertyValues来处理外部注入

最后一步 postProcessPropertyValues 注入属性

public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

InjectionMetadata metadata = this.findReferenceMetadata(beanName, bean.getClass(), pvs);

try {

metadata.inject(bean, beanName, pvs);

return pvs;

} catch (BeanCreationException var7) {

throw var7;

} catch (Throwable var8) {

throw new BeanCreationException(beanName, "Injection of @Reference dependencies failed", var8);

}

}

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

Collection checkedElements = this.checkedElements;

Collection elementsToIterate = checkedElements != null ? checkedElements : this.injectedElements;

if (!((Collection)elementsToIterate).isEmpty()) {

boolean debug = logger.isDebugEnabled();

InjectionMetadata.InjectedElement element;

for(Iterator var7 = ((Collection)elementsToIterate).iterator(); var7.hasNext(); element.inject(target, beanName, pvs)) {

element = (InjectionMetadata.InjectedElement)var7.next();

if (debug) {

logger.debug("Processing injected element of bean '" + beanName + "': " + element);

}

}

}

}

具体过程为判断当前bean 是否需要当前的processor注入 如果需要的话 即执行注入

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {

if (this.isField) {

Field field = (Field)this.member;

ReflectionUtils.makeAccessible(field);

field.set(target, this.getResourceToInject(target, requestingBeanName));

} else {

if (this.checkPropertySkipping(pvs)) {

return;

}

try {

Method method = (Method)this.member;

ReflectionUtils.makeAccessible(method);

method.invoke(target, this.getResourceToInject(target, requestingBeanName));

} catch (InvocationTargetException var5) {

throw var5.getTargetException();

}

}

}

其中 本实例中实际处理inject动作的为

private class ReferenceFieldElement extends InjectedElement

protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {

Class> referenceClass = this.field.getType();

this.referenceBean = ReferenceAnnotationBeanPostProcessor.this.buildReferenceBean(this.reference, referenceClass);

ReflectionUtils.makeAccessible(this.field);

this.field.set(bean, this.referenceBean.getObject());

}

其中具体的创建代码为

private ReferenceBean> buildReferenceBean(Reference reference, Class> referenceClass) throws Exception {

String referenceBeanCacheKey = this.generateReferenceBeanCacheKey(reference, referenceClass);

ReferenceBean> referenceBean = (ReferenceBean)this.referenceBeansCache.get(referenceBeanCacheKey);

if (referenceBean == null) {

ReferenceBeanBuilder beanBuilder = (ReferenceBeanBuilder)ReferenceBeanBuilder.create(reference, this.classLoader, this.applicationContext).interfaceClass(referenceClass);

referenceBean = (ReferenceBean)beanBuilder.build();

this.referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean);

}

return referenceBean;

}

该过程生成了一个referencebean的实例 并根据注解参数配置了

public class ReferenceBean extends ReferenceConfig

ReferenceConfig的参数。

此时执行最后一步

this.field.set(bean, this.referenceBean.getObject());

此时尝试去当前referenceBean去除绑定的 dubbo调用invoke对象 如果不存在则创建一个

具体创建过程比较长

private void init() {

// 构建参数map

this.ref = this.createProxy(map);

}

最终创建动态代理 并将ref对象赋值给@Reference注解的成员 。

完。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39624094/article/details/112995610

智能推荐

图像识别DM8127开发攻略 ——RDK软件架构浅析及编译-程序员宅基地

文章浏览阅读333次。上上一篇文章《图像识别DM8127开发攻略——开发环境搭建》介绍了DM8127的开发环境搭建,那么本篇开始描述整个IPNC RDK的架构,如果这个IPNC RDK都不熟悉,后面的移植工作基本无法进行下去,也无法深入学习和掌握DM8127的开发流程。要熟悉APPRO DM8127 软件架构,先看IPNC_RDK_InstallGuide.pdf,然后再去看看RDK包里Collaterals文件目录下..._ipnc rules.make

webstorm 2018 激活破解方法-程序员宅基地

文章浏览阅读2.8k次。首先下载补丁,看图!2017版下载地址 : 链接:https://pan.baidu.com/s/1Ed2kNzmGNrU5AsXbC2LkEw 密码:465h2018版下载地址 : 链接 : 链接: https://pan.baidu.com/s/1CYI_MjR2PC3d_H-BefYI2g 密码: zbvb这里写图片描述然后将补丁复制到安装目录的bin目录下D:\.....

Elastic:机器学习的原理及实践 - single metric job_es 机械学习的应用-程序员宅基地

文章浏览阅读6.4k次,点赞2次,收藏18次。在Elasticsearch中,可以将机器学习视为搜索和分析的自然扩展。它是对时间序列数据的分析。 Elasticsearch支持的机器学习功能可以通过运行metric任务来自动分析时间序列数据,该metric任务包含一个或多个定义了将要分析的字段的检测器。 它可以帮助我们识别单变量时间序列数据中的异常,并向我们显示正常情况。在Elasticsearch中,我们可以通过机器学习来检测时间系列中的异..._es 机械学习的应用

Android的log保存到文件上查看_android log.v 存为文件-程序员宅基地

文章浏览阅读2.1w次。在调试的时候一般都是在logcat中看日志的信息,以便找出BUG和调试信息,但是如果在真机上的话不可能一直连接电脑查看日志,所以生成日志文件并保存,是一个比较普遍的需求,下面就是最近实现的一个例子。欢迎大家讨论并给出别的思路。 import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream_android log.v 存为文件

c语言--printf--scanf--运算符_c语言带运算scanf-程序员宅基地

文章浏览阅读1.4k次。printf将变量的内容输出到显示器。四种用法:printf("字符串\n");printf("输出控制符",输出参数);printf("输出控制符1 输出控制符2...",输出参数1,输出参数2); //输出控制符和输出参数个数必须一一对应printf("输出控制符 非输出控制符",输出参数,输出参数);以%开头一般都是输出控制符,输出控制符包含如下%d %ld %f %c %lf %x %X %#X %o %s为什么需要输出控制符。01组成的代码可以表示数据也可以表示指_c语言带运算scanf

初试 Kubernetes 动态卷配置使用 RBD 作为 StorageClass_failed to provision volume with storageclass-程序员宅基地

文章浏览阅读3.7k次。目录Kubernetes StorageClass 介绍环境、软件准备Kubernetes 使用 RBD 作为 StorageClass1、Kubernetes StorageClass 介绍Kubernetes 集群存储 PV 支持 Static 静态配置以及 Dynamic 动态配置,动态卷配置 (Dynamic provisioning) 可以根据需要动态的创建存储卷。我们知道,之前的静态配..._failed to provision volume with storageclass

随便推点

MFC C++改变控件字体大小颜色的方法_cfont设置字体大小-程序员宅基地

文章浏览阅读1.4k次。MFC C++改变控件字体大小颜色的方法_cfont设置字体大小

requests(网络请求库神器 )库快速上手_requests 在线请求工具-程序员宅基地

文章浏览阅读202次。关于requests(网络请求库神器 )库快速上手urllib、urllib2、urllib3、httplib、httplib2 都是和 HTTP 相关的 Python 模块,看名字就觉得很反人类,更糟糕的是这些模块在 Python2 与 Python3 中有很大的差异,如果业务代码要同时兼容 2 和 3,写起来会让人崩溃。好在,还有一个非常惊艳的 HTTP 库叫 requests,它是 ..._requests 在线请求工具

springboot使用EntityManager执行自定义SQL_springboot 执行自定义sql-程序员宅基地

文章浏览阅读2.9k次。1.在代码中注入 EntityManager import javax.persistence.EntityManager;@AutowiredEntityManager entityManager; 2.在方法中具体使用EntityManager public List<DefColumn> findAllColumns(String table) { Query query = entityManager.createNativeQue._springboot 执行自定义sql

MSYS2安装和使用_pacman windows-程序员宅基地

文章浏览阅读546次,点赞14次,收藏12次。msys2是一款跨平台编译套件,它模拟linux编译环境,支持整合mingw32和mingw64,能很方便的在windows上对一些开源的linux工程进行编译运行。更重要的是它支持pacman包管理器;这意味着你可以很方便的安装所需要的软件包和开发库,而不需要自己去找源码编译。_pacman windows

JDK8 日期格式化_jdk date pattern-程序员宅基地

文章浏览阅读1w次。为什么要格式化我们中国人习惯 yyyy-MM-dd HH:mm:ss 这种格式的日期,但奈何框架是歪国大佬们写的,他们的日期格式与我们相差甚远,好在 Spring Boot 提供了 spring.jackson.date-format,但它只能格式化 java.util.Date。那么解决办法是什么呢?在 JDK8 中,一个新的重要特性就是引入了全新的时间和日期API,它被收录在 java..._jdk date pattern

不是python中用于开发用户界面的第三方库-Python计算生态习题(50题)-程序员宅基地

文章浏览阅读6k次,点赞3次,收藏36次。1、Python网络爬虫方向的第三方库是A. requestB. jiebaC.itchatD.time答案:A2、Python网络爬虫方向的第三方库是A、numpyB、scrapyC、ArcadeD、FGMK答案:B3、Python数据分析方向的第三方库是A、BokehB、dataswimC、scipyD、Gleam答案:C4、Python数据分析方向的第三方库是A、PlotlyB、PyQtDa..._python第三方库习题

推荐文章

热门文章

相关标签