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的更多相关文章
随机推荐
- 1. JavaScript学习笔记——JS基础
1. JavaScript基础 1.1 语法 严格区分大小写 标识符,第一个字符可以是 $,建议使用小驼峰法, 保留字.关键字.true.false.null不能作为标识符 JavaScript是用U ...
- rest-framework框架组件
序列化组件 创建一个序列化类, 视图四种方式 以下代码都需要创建一个serializers.py文件 from rest_framework import serializers from CBV_a ...
- 对java的理解
一门编程语言,分三部分. 核心语法,库,数据结构.
- jsp基础知识总结
1.了解jsp,jsp有什么有利的,有什么弊端. jsp是serlet的扩展,在web应用中,每个jsp页面都会有servlet容器生产对应的servlet. jsp通过在标准的html页面中插入ja ...
- react大纲
课程大纲: https://miaov.com/index.php/news/newsDetail/nid/263 原文件 Npm 基本使用 切换镜像, 国内的网络访问 npm 服务器可能比较慢, ...
- Oracle 数据库名、实例名、Oracle_SID
本文参考自ORACLE 数据库名.实例名.ORACLE_SID的区别,纯属读书笔记,加深记忆 在ORACLE7.8数据库中只有数据库名(db_name)和数据库实例名(instance_name).在 ...
- HTML5跨域请求--POST方式
var xmlHttp; // Create the XHR object. function createCORSRequest(method, url) { var xhr = new XMLHt ...
- 算法学习笔记之——priority queue、heapsort、symbol table、binary search trees
Priority Queue 类似一个Queue,但是按照priority的大小顺序来出队 一般存在两种方式来实施 排序法(ordered),在元素入队时即进行排序,这样插入操作为O(N),但出队为O ...
- hibernate 学习笔记3
1. 多对多关联: 在双方都要用一个类型为Set的属性保存对方的信息,并在映射配置文件中指定这个属性的名字,并指定中间表.还需要通过<key column=””>来指定自己在中间表中对应的 ...
- Hibernate项目环境搭建
1.首先在eclipse里面新建一个Java工程. 2.在数据库中新建一个数据库(无需创建表,有Hibernate生成). 3.在项目中导入Hibernate所依赖的jar包,该jar包可以在此下载: ...