在此感谢http://blog.csdn.net/quhongwei_zhanqiu/article/details/41577235。斩秋的文章。以下的大部分是在参考了斩秋的文章。
上一节简单的对dubbo的外围知识进行了简单的打探,下面开始真正进入dubbo。开启dubbo的源码探索之旅。
JDK自带的SPI正因为有在上一节提到的缺点,因此在dubbo中对其进行了扩展。这节重点来看看dubbo是怎么扩展JDK的SPI。
dubbo中定义了注解:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
/**
* 缺省扩展点名。
*/
String value() default "";
}
在dubbo中只有在接口打了@SPI注解的接口,它的实现类才会被当成扩展点的实现进行查找。
例如:接口:Protocol 被SPI注解标注,默认扩展点的名字为dubbo
@SPI("dubbo")
public interface Protocol {
//省
}
此接口的实现类(相关类):
dubbo中RPC模块默认协议(Protocol )的实现是:DubboProtocol,key:dubbo
这里插一句:dubbo加载扩展点的地方:
1)META-INF/dubbo/internal/ //dubbo内部实现的各种扩展都放在了这个目录了
2)META-INF/dubbo/
3)META-INF/services/
因此定义DubboProtocol的文件在:
查看com.alibaba.dubbo.rpc.protocol文件中的内容:
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。Protocol的其中一个扩展点就在此定义。
在文件中定义了接口的扩展点之后,最重要的就是读取配置文件中的信息,并且按需加载相应的扩展点的实现。在dubbo中ExtensionLoader类负责加载扩展点的实现。
下面来重点看看ExtensionLoader类
首先对ExtensionLoader说明一下:
1)每一个ExtensionLoader实例仅负责加载被SPI注解扩展的实现
2)每一个ExtensionLoader实例只负责加载一个特定扩展点实现
3)每一个扩展点(一个被SPI注解的接口)对应最多只有一个ExtensionLoader实例
4)每一个扩展点对应最多只有一个ExtensionLoader实例
5)对于每一个扩展点的每一个实现类,只会有一个实例。
下面介绍一下ExtensionLoader类中的几个重点方法:
1,ExtensionLoader.getExtensionLoader(Protocol.class)
根据接口类型创建一个ExtensionLoader并且放入缓存中:EXTENSION_LOADERS(一个静态对象),如果已经存在了该接口类型的ExtensionLoader实例,就直接返回。
2,loadExtensionClasses():
读取扩展点中的实现类
1)先读取SPI注解的value值,如果有作为默认扩展实现类的key。
2)依次读取路径的文件
META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol
META-INF/services/com.alibaba.dubbo.rpc.Protocol
3,loadFile():
逐行读取com.alibaba.dubbo.rpc.Protocol文件中的内容,每行内容以key/value形式存储。
1)判断实现类上有没有被@Adaptive注解:
11)如果被@Adaptive的注解,将此实现类作为Protocol的适配类缓存起来,赋值给cachedAdaptiveClass属性,(只能有一个@Adaptive实现类,出现第二个就会报错了)。
12)如果没有被@Adaptive注解,
121)判断实现类是否存在入参为接口的构造器,如果存在作为包装类缓存到Set<Class<?>> cachedWrapperClasses中(装饰模式)
122)如果不是适配类不是包装类,就是扩展点的具体实现对象。将实现类缓存到cachedClasses属性中。
4,创建或获取适配对象getAdaptiveExtension
1)如果cachedAdaptiveClass有值,说明有且仅有一个实现类打了@Adaptive。
Object instance = cachedAdaptiveInstance.get();
2)如果cachedAdaptiveClass为空, 创建适配类字节码
为什么要创建适配类?一个接口多种实现,SPI机制也是如此,这是策略模式。但是我们在代码执行过程中选择哪种具体的策略呢?Dubbo采用统一数据模式com.alibaba.dubbo.common.URL(它是dubbo定义的数据模型不是jdk的类),它会穿插于系统的整个执行过程,URL中定义的协议类型字段protocol,会根据具体业务设置不同的协议。url.getProtocol()值可以是dubbo也是可以webservice。
适配类的作用是根据url.getProtocol()的值extName,去ExtensionLoader. getExtension( extName)选取具体的扩展点实现。
插一句:
能够利用javasist生成适配类的条件
1)接口方法中必须至少有一个方法打上了@Adaptive注解
2)打上了@Adaptive注解的方法参数必须有URL类型参数或者有参数中存在getURL()方法。
5,通过createAdaptiveExtensionClassCode()会生成Protocol接口的适配类的java源码代码。如果生成的适配类源码要被java虚拟机加载执行的话,那必须编译成字节码。dubbo提供两种方式去执行代码的编译1)利用JDK工具类编译2)利用javassit根据源代码生成字节码。
后面会专门探索一下dubbo中的compiler接口。
@Adaptive注解在实现类上和在接口方法上的区别:
1)在实现类上:通过获取扩展文件的时候遇到注解@Adaptive,就把这个类作为适配类缓存在ExtensionLoader中,调用的时候直接返回。
2)在接口上:首先生成JAVA代码。在通过编译器编译成class加载。
6,自动Wrap上扩展点的Wrap类
我们还是拿protocol来说,ProtocolFilterWrapper, ProtocolListenerWrapper这个两个类是装饰对象实现protocol,用来增强其他扩展点实现的功能。ProtocolFilterWrapper功能主要是在refer 引用远程服务的中透明的设置一系列的过滤器链用来记录日志,处理超时,权限控制等等功能;ProtocolListenerWrapper在provider的exporter,unporter服务和consumer的refer服务,destory调用时添加监听器,dubbo提供了扩展但是没有默认实现哪些监听器。
Dubbo是如何自动的给扩展点wrap上装饰对象的呢?
1)在ExtensionLoader.loadFile加载扩展点配置文件的时候
对扩展点类有接口类型为参数的构造器就是包转对象,缓存到集合中去
2)在调ExtensionLoader的createExtension(name)根据扩展点key创建扩展的时候, 先实例化扩展点的实现, 在判断时候有此扩展时候有包装类缓存,有的话利用包转器增强这个扩展点实现的功能。
private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(name);//获取name对应的扩展类型
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);//扩展点注入
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
//循环遍历所有wrapper实现,实例化wrapper并进行扩展点注入
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}
7. dubbo的ExtensionLoader在加载扩展实现的时候内部实现了个简单的ioc机制来实现对扩展实现所依赖的参数的注入,dubbo对扩展实现中公有的set方法且入参个数为一个的方法,尝试从对象工厂ObjectFactory获取值注入到扩展点实现中去。
/**
* 扩展点参数的自动注入
* @param instance
* @return
*/
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {// 处理所有set方法
Class<?> pt = method.getParameterTypes()[0];// 获取set方法参数类型
try {
// 获取setter对应的property名称
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property);// 根据类型,名称信息从ExtensionFactory获取
if (object != null) {
method.invoke(instance, object);
// 如果不为空,说set方法的参数是扩展点类型
// instance对象调用method方法,参数为object
// 这样来实现动态注入
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
AdaptiveExtensionFactory持有所有ExtensionFactory对象的集合,dubbo内部默认实现的对象工厂是SpiExtensionFactory和SpringExtensionFactory,他们存放在ArrayList对象中,getExtension(Class<T> type, String name)遍历获取Extension对象,如果遍历完集合中没有找到扩展对象,就返回NULL。
1)SpiExtensionFactory工厂获取要被注入的对象,就是要获取dubbo spi扩展的实现,所以传入的参数类型必须是接口类型并且接口上打上了@SPI注解,返回的是一个适配类对象。
2) SpringExtensionFactory,Dubbo利用spring的扩展机制跟spring做了很好的融合。在发布或者去引用一个服务的时候,会把spring的容器添加到SpringExtensionFactory工厂集合中去, 当SpiExtensionFactory没有获取到对象的时候会遍历SpringExtensionFactory中的spring容器来获取要注入的对象。
最后附上一个活动图(参照斩秋博主的所画):
总结:
ExtensionLoader加载扩展点的各种类型的实现类
适配类:每个扩展点只会有一个适配实现类出现。如果没有找到适配类,会使用JDK动态代理或者是javasist动态生成一个。
装饰类:实现类是否存在入参为接口的构造函数,如果有就是装饰类。可以多个
实现类:如果不是适配类不是包装类,就是扩展点的具体实现对象
以上是我个人的对dubbo的一些见解,欢迎大家一起讨论!
下一节,我想看看ExtensionFactory
- 大小: 37 KB
- 大小: 13.3 KB
- 大小: 149.7 KB
分享到:
相关推荐
dubbo-admin安装要点: 1.清空tomcat/webapps/ROOT目录 2.将包解压到tomcat/webapps/ROOT下 3.修改tomcat/webapps/ROOT/WEB-INF/dubbo.properties 文件 dubbo.registry.address dubbo接口服务注册地址: 单机...
【Dubbo-Admin JDK8 编译详解】 Dubbo-Admin 是阿里巴巴开源的分布式服务治理平台,它提供了服务注册、服务发现、服务监控等能力,是Dubbo框架的重要组成部分。在JDK8环境下编译Dubbo-Admin,可以确保与Java 8的...
dubbo-admin在jdk1.8环境下运行,dubbo-admin在jdk1.8环境下运行dubbo-admin在jdk1.8环境下运行dubbo-admin在jdk1.8环境下运行dubbo-admin在jdk1.8环境下运行dubbo-admin在jdk1.8环境下运行dubbo-admin在jdk1.8环境下...
【标题】"dubbo-admin jdk1.8可用"指的是Dubbo管理控制台dubbo-admin在Java Development Kit(JDK)版本1.8环境下可以正常运行。Dubbo是中国阿里巴巴开源的一个高性能、轻量级的服务治理框架,它提供服务发现、服务...
【标题】"dubbo-admin jdk8" 涉及的核心知识点主要集中在 Dubbo 的管理控制台 Dubbo-admin 和其对 Java 开发环境 JDK8 的依赖。Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,主要用于服务治理,而 Dubbo-admin ...
【标题】"dubbo-admin-2.5.4-SNAPSHOT-jdk8"指的是Dubbo管理控制台的一个特定版本,适用于Java 8环境。Dubbo是阿里巴巴开源的一款高性能、轻量级的服务治理框架,主要用于实现分布式服务的治理,提供服务的注册、...
dubbo源码dubbo-dubbo-2.7.3.rardubbo源码dubbo-dubbo-2.7.3.rardubbo源码dubbo-dubbo-2.7.3.rardubbo源码dubbo-dubbo-2.7.3.rardubbo源码dubbo-dubbo-2.7.3.rardubbo源码dubbo-dubbo-2.7.3.rardubbo源码dubbo-dubbo...
【标题】"dubbo-admin-jdk1.8环境可用.zip" 涉及的主要知识点是Dubbo Admin的兼容性问题,特别是与Java 1.8版本的集成。Dubbo是一款高性能、轻量级的开源Java RPC框架,由阿里巴巴提供。在分布式系统中,它主要负责...
根据描述,本教程推荐的dubbo-admin版本是与JDK 1.8及以上版本兼容的,这意味着你需要先确保你的开发环境中已经安装了Java 8或者更高版本。 1. **Java环境配置**:首先,你需要在你的机器上安装Java Development ...
解决dubbo-admin在jdk1.8下启动报错问题,需要下载dubbo源码修改问题重新编译打包发布,这里已经和重新编译。
dubbo -admin-2.5.4 不兼容 jdk1.8版本 会报错 下面修改后的dubbo-admin -jdk1.8 亲测可用 下载解压后 改成 工程ROOT 全部放在Tomcat webapps 下 作为ROOT 目录即可使用~~~
【标题】"incubator-dubbo-dubbo-2.5.8" 是一个基于Java的开源服务框架,由Apache孵化器项目提供。这个版本是Dubbo的2.5.8稳定版,它包含了Dubbo的核心服务治理功能以及一个专门的管理平台——dubbo-admin。 【描述...
【标题】"dubbo-admin-2.5.4.war" 指的是 Dubbo 提供的一款基于 Web 的管理控制台应用,版本为 2.5.4。这个 WAR 文件是一种打包好的 Java Web 应用程序,可以在支持 Java Servlet 的容器(如 Apache Tomcat)上部署...
本篇将详细讲解基于dubbo-demo-consumer、dubbo-demo-provider和dubbo-simple-monitor的实例服务,带你深入理解Dubbo的核心概念和操作流程。 首先,我们来看`dubbo-demo-consumer`,它是Dubbo服务的消费者。消费者...
【标题】"incubator-dubbo-dubbo-2.6.1" 是一个Apache Incubator项目Dubbo的特定版本,这里的2.6.1表示该版本是Dubbo的稳定分支之一。 【描述】提到的"incubator-dubbo-dubbo-2.6.1"表明这是Apache孵化器中的Dubbo...
JDK8引入了模块系统(Project Jigsaw),尽管`dubbo-admin`本身并不直接依赖这个特性,但作为一个独立的服务治理工具,它可以借鉴模块化的思想进行设计,提高代码的可维护性和可扩展性。 4. 兼容性与稳定性 JDK8的...
《Apache Incubator Dubbo-OPS Master:深度解析与实践》 Apache Incubator Dubbo-OPS Master 是一套由Dubbo社区开发的管理工具,旨在为Dubbo服务提供全面的运营管理和监控支持。Dubbo,作为一款高性能、轻量级的...
【标题】"dubbo-admin包"是Dubbo框架的一个重要组成部分,主要用作服务治理的管理界面。这个压缩包包含了运行Dubbo管理控制台所需的所有文件,使得开发者和运维人员可以方便地监控、管理和配置Dubbo服务。 【描述】...
dobbo源码dubbo-dubbo-2.7.3.rardobbo源码dubbo-dubbo-2.7.3.rardobbo源码dubbo-dubbo-2.7.3.rardobbo源码dubbo-dubbo-2.7.3.rardobbo源码dubbo-dubbo-2.7.3.rardobbo源码dubbo-dubbo-2.7.3.rardobbo源码dubbo-dubbo...
其中,`dubbo-admin`是Dubbo的核心组件之一,它提供了一个可视化的管理控制台,帮助开发者对服务进行管理和监控。本文将详细解析`dubbo-admin-2.5.4.war`这个版本的后台管理工具,探讨其主要特性和使用方法。 首先...