dubbo AdaptiveExtension
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
// 获得AdaptiveExtension入口
public T getAdaptiveExtension() {
// cachedAdaptiveInstance缓存
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {// 缓存没有
// 判断创建时有没有报错过
if(createAdaptiveInstanceError == null) {
// 这种是经典的同步写法,先取一下,没有的话,再锁住,然后再取一下,而不是直接锁。
synchronized (cachedAdaptiveInstance) {
// 再取
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 创建
instance = createAdaptiveExtension();
// 放缓存
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
// 这里先把出错打标记,如此如果外界再次调用即可直接返回,这里就没有重试,一次失败,认为就都失败,防止了并发调用大量相同报错
createAdaptiveInstanceError = t;
throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
}
}
}
}
else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
} return (T) instance;
} private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
}
} private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
// 依然没有cachedAdaptiveClass 说明没有配置@Adaptive 那就自动生成一个
return cachedAdaptiveClass = createAdaptiveExtensionClass();
} private Class<?> createAdaptiveExtensionClass() {
// 组装java代码
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
// 编译出来
return compiler.compile(code, classLoader);
} private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
} private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if(defaultAnnotation != null) {
String value = defaultAnnotation.value();
if(value != null && (value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if(names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if(names.length == 1) cachedDefaultName = names[0];
}
} Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadFile(extensionClasses, DUBBO_DIRECTORY);
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
以下方法都会触发loadFile,这个方法就会读取文件,解析出各个插件的class。有@Adaptive注解的会放入赋值给cachedAdaptiveClass。
下面以Transporter接口为例进行说明自动生成的代码:
@SPI("netty")
public interface Transporter {
@Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
Server bind(URL url, ChannelHandler handler) throws RemotingException;
@Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
Client connect(URL url, ChannelHandler handler) throws RemotingException;
}
动态生成类:
public class Transporter$Adaptive implements Transporter {
public Server bind(URL arg0, ChannelHandler arg1) throws RemotingException {
URL url = arg0;
String extName = url.getParameter("server",
url.getParameter("transporter", "netty"));
Transporter extension = (Transporter) ExtensionLoader
.getExtensionLoader(Transporter.class).getExtension(extName);
return extension.bind(arg0, arg1);
}
}
Adaptive机制是一个很好的设计,很好的解决多方案实现的适配问题,如果你遇到类似的代码架构的时候,多想一下更加有扩展性的设计。
dubbo AdaptiveExtension的更多相关文章
- dubbo源码—SPI
Java中的SPI SPI,Service Provider Interface,java中提供的一种使程序可扩展的方式,系统定义好接口规范,供其他服务提供方实现,服务提供方将自己jar包META-I ...
- Dubbo中SPI扩展机制解析
dubbo的SPI机制类似与Java的SPI,Java的SPI会一次性的实例化所有扩展点的实现,有点显得浪费资源. dubbo的扩展机制可以方便的获取某一个想要的扩展实现,每个实现都有自己的name, ...
- 【Dubbo 源码解析】02_Dubbo SPI
Dubbo SPI:(version:2.6.*) Dubbo 微内核 + 插件 模式,得益于 Dubbo SPI .其中 ExtentionLoader是 Dubbo SPI 最核心的类,它负责扩展 ...
- dubbo ActivateExtension
对于集合类扩展点,比如:Filter, InvokerListener, ExportListener, TelnetHandler, StatusChecker等, 可以同时加载多个实现,此时,可以 ...
- Dubbo(2)--Dubbo常用配置文件解析及核心源码阅读
1.多版本支持 服务端 创建第二个接口实现类 package com.lf; public class HelloImpl2 implements IHello{ @Override public S ...
- 第四章 dubbo内核之aop源码解析
ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class); final P ...
- dubbo源码分析之基于SPI的强大扩展
https://blog.csdn.net/luoyang_java/article/details/86609045 Dubbo采用微内核+插件体系,使得设计优雅,扩展性强.那所谓的微内核+插件体系 ...
- dubbo源码分析01:SPI机制
一.什么是SPI SPI全称为Service Provider Interface,是一种服务发现机制,其本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件.这样可以在运行时,动态为 ...
- Dubbo源码分析(5):ExtensionLoader
背景 Dubbo所有的模块加载是基于SPI机制的.在接口名的上一行加个@SPI注解表明要此模块要通过ExtensionLoader加载.基于SPI机制的扩展性比较好,在不修改原有代码,可以实现新模块的 ...
随机推荐
- 【转】js 对象按照键值(不分区大小写)排序,生成签名方法
客户需求小程序端用js生成签名,我们按照要求一步一步解决,并且将请求方法封装到一个utils.js里: 第一步:对关联数组按照键名做正序排序. 第二步:拼接字符串 第三步:将拼接的字符串加上私钥 第四 ...
- 顺序容器----顺序容器操作,vector对象如何增长,额外的string操作,容器适配器
一.顺序容器操作 1.向顺序容器添加元素 向顺序容器(array除外)添加元素的操作: 操作 说明 c.push_back(t) 在c的尾部创建一个值为t的元素.返回void c.emplace_ba ...
- matlab 调试日志
debug=; diary off if debug delete('log.txt'); !del log.txt diary('log.txt'); diary ON end diary OFF
- VMware 安装 centos,自定义分区
具体查看:https://jingyan.baidu.com/album/6525d4b1799149ac7d2e9483.html?picindex=11
- laravel中使一段文字,限制长度,并且超出部分使用指定内容代替
{{str_limit($post->content,100,'....')}} 文字内容超出100个字,就用省略号显示
- Fiddler系列教程2:手机抓包图文教程
上篇Fiddler教程,我们教了大家Fiddler安装配置及如何使用Fiddler进行基本的Http抓包及模拟请求,今天给大家介绍下如何使用Fiddler进行手机抓包. 运行环境为Windows 10 ...
- react+dva+antd/antd-mobile
github仓库pc: https://github.com/llcMite/react-dva-antd.git github仓库mobile:https://github.com/llcMite/ ...
- 福大软工1816 · 第三次作业 - 结对项目Salty Fish原型图
SALTY FISH原型图 LINKS IMPORT to LIST FOCUS TRENDS ANALYSE NIGHT
- 下载hibenate tools插件(百度搜hibenate tools 下载)
Eclipse插件的安装和使用1. 在线更新( http://blog.csdn.net/charlies_fu/article/details/5638068)打开eclipse工具,选择H ...
- 在ros功能包CMakeLists.txt中获取所在功能包的路径 便于添加第三方库的相对路径
在 ros 功能包中要使用第三方的动态库,将其放在系统默认库路径和使用绝对路径均不可取,这样的话可移植性较差,将该功能包移到其它电脑时要重新配置依赖库的路径,太麻烦了. 于是找到下面这个方法,解决了R ...