技术标签: 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注解的成员 。
完。
文章浏览阅读215次。内容简介前言文件的打开和关闭读写文件的不同方法在文件中移动文件的重命名和删除第二部分第八课预告1. 前言上一课 C语言探索之旅 | 第二部分第六课:创建你自己的变量类型 之后,我们来学习很常用的文件读写。我们学过了这么多变量的知识,已经知道变量实在是很强大的,可以帮助我们实现很多事情。变量固然强大,还是有缺陷的,最大的缺陷就是:不能永久保存。因为 C语言的变量储存在内存中,在你的程序退出..._怎么将txt文件保存在r工作环境所在的目录下
文章浏览阅读118次。<?xml version="1.0" encoding="UTF-8"?><xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://java.sun.com/xml/ns/j2ee" xmlns:j2ee="http://java..._servlet-3_0 final-spec 中文版
文章浏览阅读1.6k次。lua函数之rawget和rawset的应用_lua rewget
文章浏览阅读85次。我对所使用的“搜狗输入法”的看法: 用户界面:1、界面简约精美,可切换风格皮肤,给用户较好的外观体验。 2、不使用的时候自动隐藏,较好的迎合用户的主要操作。 记住用户选择:输入法皮肤的使用、中英文切换。 短期刺激:打字时弹出的界面有特效,看起来很好。 长期使用的好处坏处:长期使用时能记录用户的常用字或词,特别方便。 不要让用户犯简单的错误:有词的自动..._每个人评价一下大家手头正在使用输入法或者搜索类的软件产品。 从用户界面、记住
文章浏览阅读3.2k次。 我作为一个核专业的专业,就给大家简单的说明一下,福岛核电站泄漏事故固然有天灾的缘故,但其背后隐藏着人为设计缺陷的必然性。 一、日本处于环太平洋火山带上,是一个地震高发国家。福岛核电站就位于地震带上。而我国核电站已充分考虑了地质结构的稳定性要求,同时考虑了海啸的影响。 二、福岛核电站在全部失去场内外电源的情况下,就会失去堆芯冷却的全部功能。而我国建设的压水堆核电站即使失去全部厂内外电源,也能通过自带的气动给水泵和蒸汽排放的形式维持对堆芯的冷却。 三、福岛核电站没有安全壳。虽然在200_福岛核泄漏事故原因
文章浏览阅读4.5k次。1 工具下载测试工具使用ONVIF Device Test Tool,具体下载地址可自行百度,一路默认安装即可。2 相机配置我使用的海康球机型号为DS-2DE2402IW-DE3/W,默认是没有打开ONVIF协议的,需要我们在配置中进行配置进入海康相机设置平台,选择配置-高级配置-勾选启用ONVIF-添加用户-输入登陆用户名和密码-保存以上即可完成相机ONVIF的相关配置3 连接设备..._onvif扫描工具
文章浏览阅读5k次,点赞9次,收藏15次。KMany Littles Make a Mickle题目大意:有t组输入,每组输入一个n,一个m,表示有n层,第i层有i*i个房间,每个房间有m个人,求有多少人。题解:数据小,暴力求和即可(也可直接输出i^2求和公式但是赛时没想那么多)#include <bits/stdc++.h>#define int long longusing namespace std;signed main(){ int t = 0; cin >> t; int n,m;_21年工控大赛 江西站题目
文章浏览阅读1.4k次,点赞2次,收藏2次。这些模型增强是在 ABAP 服务器的事物码SEGW里完成的。我们在 SEGW 里创建了Authors这个 Navigation Properties,它通过名为BookAuthor的 Relationship,依据 Book 和 Author 两个 Entity Type 的book_guid字段,描述了这两个节点间的导航关系,即通过一个 Book 实例,我们期望通过$expand操作,读取到其所有的 Authors 数据:其中绿色的位于$expand=_sap odata expand 方法debug
文章浏览阅读2k次。一、zint1. 介绍Zint是一个软件,允许在任何广泛的公共领域条形码标准中轻松编码数据,并允许将这种功能集成到您自己的程序中。Zint项目的目标是提供一个完全跨平台的开源条形码生成解决方案,目前包含了:一个基于Qt的基础GUI一个命令行工具一个允许用户调用API使用Zint的库2. 下载zint在github的仓库地址为:https://github.com/zint..._zint库
文章浏览阅读880次。这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Ma..._macbookpro stm32f1
文章浏览阅读572次。Qt C++图形用户界面应用程序开发框架。Qt的由来和发展 1、QT由来 Haavard Nord 和Eirik Chambe-Eng于1991年开始开发"Qt",1994年3月4日创立公司,早名为Quasar Technologies,然后更名为Troll Tech,然后在改为Trolltech,中文名是“奇趣科技”。2008年6月17日被NOKIA公司收购,以增强该..._qt gdk
文章浏览阅读149次。[img]http://dl.iteye.com/upload/attachment/439950/70a7638d-3ef9-33e7-b392-a8bcfe7b60ad.png[/img]_process addresss space