04_dubbo_ioc
【dubbo的IOC实现方法】
dubbo的IOC具体实现在:T injectExtension( T instance )方法中,该方法在3个地方被使用:
ExtensionLoader.getExtensionLoader(Protocol.class)
--new ExtensionLoader<T>(type)
----getAdaptiveExtension()
------createAdaptiveExtension()
/**1.为创建好的AdaptiveExtensionClass实例进行属性注入**/
--------injectExtension((T) getAdaptiveExtensionClass().newInstance()) /**2.为创建好的Extension实例进行属性注入**/
ExtensionLoader.getExtension("dubbo")
--createExtension("dubbo")
----injectExtension(instance);
/**3.为创建好的wrapperClass实例进行属性注入**/
----injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) //
【 injectExtension( T instance )源码】
injectExtension( T instance )方法的作用是通过instance对象的实例的setXxx(object)方法为instance的属性进行赋值,完成setter注入,类似Spring的ioc的经典注入方式。
详细步骤:
1.获取instance的setXxx方法,通过setXxx方法获取属性名称property和属性类型pt。
2.使用objectFactory创建属性property的对象实例object
3.执行method.invoke( instance, object ),注入property实例,即执行setXxx(object)方法
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
//成员变量的setXxx(T param)方法,例如:setName(String name)
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
//获取参数param的类型的Class对象
Class<?> pt = method.getParameterTypes()[0];
try {
//通过方法名setXxx获取成员变量名xxx,例如setName-->name
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
//实例化参数object
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
//执行instance实例对应的setXxx(object)方法,参数是object
method.invoke(instance, 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;
}
其中,比较重要的是
Object object = objectFactory.getExtension(pt, property);
这个方法,其中的ExtensionFactory objectFactory实例为 AdaptiveExtensionFactory实例,即
//伪代码
ExtensionFactory objectFactory = AdaptiveExtensionFactory实例

AdaptiveExtensionFactory的成员变量
factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]
【 AdaptiveExtensionFactory 类源代码】
/**
* AdaptiveExtensionFactory
*
* @author william.liangf
*/
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() {
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
} /**
* 先调用SpiExtensionFactory来实例化
* 如果不行,再使用SpringExtensionFactory来实例化
**/
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
} }
【SpiExtensionFactory源码】
/**
* SpiExtensionFactory
*
* @author william.liangf
*/
public class SpiExtensionFactory implements ExtensionFactory { public <T> T getExtension(Class<T> type, String name) {
//type是接口类型,且必须含有@SPI注解
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
//获取type的所有ExtensionClasses实现的key(例如:type是Protocol.class)
if (loader.getSupportedExtensions().size() > 0) {
//获取type的装饰类,如果有@Adaptive注解的类,则返回该类的实例,否则返回一个动态代理的实例(如:Protocol$Adaptive 的实例)
return loader.getAdaptiveExtension();
}
}
return null;
} }
结论:dubbo-spi相对于JDK-spi的一个好处,可以为SPI实现类注入SPI的装饰类或动态代理类。
【 SpringExtendsionFactory的源码 】
/**
* SpringExtensionFactory
*
* @author william.liangf
*/
public class SpringExtensionFactory implements ExtensionFactory { private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>(); public static void addApplicationContext(ApplicationContext context) {
contexts.add(context);
} public static void removeApplicationContext(ApplicationContext context) {
contexts.remove(context);
} @SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
//该context是否包含name的bean
if (context.containsBean(name)) {
//获取该name对应的bean,如果是懒加载或者多实例的bean,此时会实例化name对应的bean
Object bean = context.getBean(name);
//如果obj的类型是typ或者其子类,与instance相同
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
return null;
} }
【参考文章】
https://www.cnblogs.com/java-zhao/p/7469786.html
04_dubbo_ioc的更多相关文章
随机推荐
- (转载)一位资深程序员大牛给予Java初学者的学习建议
这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的,能不能给点建议? 今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要 ...
- [原创]SSH密钥访问Git仓库配置
SSH密钥并非为了解决拉取git仓库代码时,需要频繁输入密码的问题. SSH是一种比较安全的协议,可以用来免去远程登录Linux等服务器时需要输入密码的繁琐过程. 命令: ssh user@serve ...
- JAVA数据结构--二叉查找树
二叉查找树定义 二叉查找树(英语:Binary Search Tree),也称二叉搜索树.有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tr ...
- sql语句之group_concat函数
MySQL中group_concat函数 完整的语法如下: group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator '分隔 ...
- Postman学习(压力测试)
Postman下载安装后 下面是在网上随便抓了一个请求地址来做演示,把请求地址填入地址栏,此请求为GET请求.点击Send发送请求,请求结果将会在下方显示出来.每次的请求历史数据,会被记录下来,但是经 ...
- 在 Linux 服务器上部署 nginx 之后不能访问
原文地址:https://blog.csdn.net/lipeigang1109/article/details/73295373 解决办法:https://jingyan.baidu.com/art ...
- 下载Kitti 数据集(dataset) data_road.zip
官网下载http://www.cvlibs.net/download.php?file=data_road.zip,耗时近3小时,虽然只有几百兆. 但是,我坚持下来了. 保存到了百度网盘,以供国内用户 ...
- VirtualBox 命令行操作
vboxmanage list vmsvboxmanage list runningvmsvboxmanage startvmvboxmanage controlvm "RHEL6.1_fo ...
- selenium+Python(Js处理日历控件)
日历控件是web网站上经常会遇到的一个场景,有些输入框是可以直接输入日期的,有些不能,以我们经常抢票的12306网站为例,详细讲解如何解决日历控件为readonly属性的问题. 基本思路:先用js去掉 ...
- mac 下安装 mit-scheme
这两天心血来潮想看一下 SICP 和 Lisp,准备先看 SICP ,之后再学 Haskell, 深入学习一下函数式编程. 所以得装个 mit-scheme 做练习. 尝试了 3 种方式, 前 2 种 ...