在 ExtensionLoader 类的loadFile方法中有下图的这段代码:

类如现在这个ExtensionLoader中的type 是Protocol.class,也就是SPI接口的实现类中XxxProtocol类中有这样的构造函数 public XxxProtocol ( Protocol  object) ,这个构造函数显然说明XxxProtocol有包装或代理这个object的意思。所以当发现了这样特点的实现类后,就会把它缓存到wrappers这个变量中,最终缓存在ExtensionLoader的实例属性 cachedWrapperClasses中。

真正进行AOP切面包装的代码是在 createExtension方法中,标红的这段代码:

 private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(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) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); //用wrapper类的实例代替原有的instance ,但注意原有的instance作为wrapper的构造参数传入其内部了
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}

下面通过一个实例来分析下,看这段代码:

@Test
public void test(){
ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Protocol.class) ;
Protocol protocol = (Protocol) extensionLoader.getExtension("dubbo") ;
System.out.println(protocol );
}

上面这段代码执行后我们会发现输出的对象的类名是com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper,显然得到的protocol对象已经是经过包装了,而且是有两个包装对象类:

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper 和 com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper ,打开这两个类的源码,我们会发现它们都会有带Protocol参数的构造函数

public ProtocolListenerWrapper(Protocol protocol){
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
} public ProtocolFilterWrapper(Protocol protocol){
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}

所以当我们获取Protocol的某个实现时,就会被这两个类所包装。

dubbo源码分析6——SPI机制中的AOP的更多相关文章

  1. dubbo源码分析2——SPI机制中的SPI实现类的读取和预处理

    SPI机制中的SPI实现类的读取和预处理是由ExtensionLoader类的loadFile方法来完成的 loadFile方法的作用是读取dubbo的某个SPI接口的spi描述文件,然后进行缓存,缓 ...

  2. dubbo源码分析3——SPI机制中的ExtensionLoader类的objectFactory属性分析

    ExtensionLoader类是整个SPI的核心类,每个SPI都会对应一个ExtensionLoader类实例,这个类的构造方法如下: private ExtensionLoader(Class&l ...

  3. Dubbo源码分析之 SPI(一)

    一.概述 dubbo SPI 在dubbo的作用是基础性的,要想分析研究dubbo的实现原理.dubbo源码,都绕不过 dubbo SPI,掌握dubbo SPI 是征服dubbo的必经之路. 本篇文 ...

  4. Dubbo源码分析之SPI(二)

    一.概述 本篇文章是dubbo SPI源码分析的第二篇,接着第一篇继续分析dubbo SPI的内容,我们主要介绍 getDefaultExtension() 获取默认扩展点方法. 由于此方法比较简单, ...

  5. dubbo源码分析5——SPI机制_AdaptiveExtension的原理和作用

    private T createAdaptiveExtension() { try { return injectExtension((T) getAdaptiveExtensionClass().n ...

  6. dubbo源码分析4——SPI机制_ExtensionFactory类的作用

    ExtensionFactory的源码: @SPI public interface ExtensionFactory { /** * Get extension. * * @param type o ...

  7. dubbo源码分析1——SPI机制的概要介绍

    插件机制是Dubbo用于可插拔地扩展底层的一些实现而定制的一套机制,比如dubbo底层的RPC协议.注册中心的注册方式等等.具体的实现方式是参照了JDK的SPI思想,由于JDK的SPI的机制比较简单, ...

  8. Dubbo源码分析之SPI(三)

    一.概述 本篇介绍自适应扩展,方法getAdaptiveExtension()的实现.ExtensionLoader类本身很多功能也使用到了自适应扩展.包括ExtensionFactory扩展. 通俗 ...

  9. dubbo源码分析6-telnet方式的管理实现

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

随机推荐

  1. sql server开发工具

    查询分析器的使用 SQL语言包含四个部分: 1.数据定义语言(DDL) : 例如 create, drop, alter等语句 2.数据操作语言(DML) : 例如 insert,delete, up ...

  2. HDU 1030(三角数阵 数学)

    题意是问在给定的三角形数阵中从一个数到另一个数所要跨过的边数. 最初的时候很迷,除了发现每层的数字个数与层数间的关系和每层数最后一个数与层数的关系外什么也没看出来,打算先求出数字所在的层数,然后计算到 ...

  3. python代码块和小数据池

    id和is 在介绍代码块之前,先介绍两个方法:id和is,来看一段代码 # name = "Rose" # name1 = "Rose" # print(id( ...

  4. vue 中 使用百度编辑器 UEditor

    (单页应用,多编辑器也可行) 新建一个Ueditor.vue组件对象,该组件用来封装ueditor,用来进行复用. <template> <div> <!--下面通过传递 ...

  5. Newtonsoft.Json添加项

    JObject jo = (JObject)JsonConvert.DeserializeObject(result); ") { string domain=(jo["data& ...

  6. Python中json一点小知识

    import json dic={ "name":"杨林" } ret=json.dumps(dic,ensure_ascii=False) #因为json.d ...

  7. Linux 下磁盘挂载

    Linux 磁盘挂载 新硬盘挂载: fdisk /dev/sdb p # 打印分区 d # 删除分区 n # 创建分区,(一块硬盘最多4个主分区,扩展占一个主分区位置.p主分区 e扩展) w # 保存 ...

  8. nth-of-type(n)

    :nth-of-type(n) 选择器匹配属于父元素的特定类型的第 N 个子元素的每个元素. p:nth-of-type(2) { background:#ff0000; } 规定属于其父元素的第二个 ...

  9. Java SE之正则表达式二:匹配

    package demo.regex; import java.util.regex.Pattern; /* 正则表达式:匹配 */ public class RegexMatchesDemo { / ...

  10. Hadoop思维导图之概述