阅读此篇文章以前,建议先学习该系列前面几篇文章,会有一个更好的理解
.
参考: Dubbo的SPI机制分析2-Adaptive详解、Dubbo的SPI机制分析3-Dubbo的IOC依赖注入java
// 在原有接口、实现类的基础上再加一个Wrapper实现类 public class AdaptiveExtWrapper implements AdaptiveExt { private AdaptiveExt adaptiveExt; // 实现一个Wrapper类的关键就是提供一个带相似参数的构造函数,后面代码会分析 public AdaptiveExtWrapper(AdaptiveExt adaptiveExt) { this.adaptiveExt = adaptiveExt; } @Override public String echo(String msg, URL url) { // do something,实现了AOP System.out.println("before"); adaptiveExt.echo(msg, url); System.out.println("after"); // do something return "wrapper"; } }
public class DubboAdaptiveExt implements AdaptiveExt { private AdaptiveExt adaptiveExt; // 此处DubboAdaptiveExt依赖注入一个AdaptiveExt 类型的实例,此处测试用例注入的是ThriftAdaptiveExt public void setAdaptiveExt(AdaptiveExt adaptiveExt) { this.adaptiveExt = adaptiveExt; } @Override public String echo(String msg, URL url) { System.out.println(this.adaptiveExt.echo(msg, url)); return "dubbo"; } } @Test public void test1(){ ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class); AdaptiveExt adaptiveExtension = loader.getExtension("dubbo"); URL url = URL.valueOf("test://localhost/test"); adaptiveExtension.echo("d", url); }
同时记得dubbo的配置文件中要新增一行,不然dubbo框架没法扫描到Wrappersegmentfault
dubbo=com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt cloud=com.alibaba.dubbo.demo.provider.adaptive.impl.SpringCloudAdaptiveExt thrift=com.alibaba.dubbo.demo.provider.adaptive.impl.ThriftAdaptiveExt com.alibaba.dubbo.demo.provider.adaptive.impl.AdaptiveExtWrapper
运行代码,输出: before thrift after
能够发现,上述代码前后输出before、after,中间输出thrift,这其实能够说明adaptiveExtension = loader.getExtension("dubbo")返回的是AdaptiveExtWrapper类型的实例,有点像静态代理,下面分析源代码.app
// 核心代码,删去一些不重要代码 private T createExtension(String name) { // 这里也是经过dubbo的SPI机制去扫描dubbo的默认目录下的文件,去加载实现了AdaptiveExt的实现类,这里会 // 加载4个,包括AdaptiveExtWrapper,它就是下面的wrapperClasses中仅有的元素,下面先分析这个加载过程 Class<?> clazz = getExtensionClasses().get(name); try { T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } // 依赖注入,这里注入的就是ThriftAdaptiveExt类型的实例对象 injectExtension(instance); // 因此这里面cachedWrapperClasses包含了AdaptiveExtWrapper类 Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && !wrapperClasses.isEmpty()) { for (Class<?> wrapperClass : wrapperClasses) { // 先分析仅有一个Wrapper类的状况,将原有的instance做为参数传入AdaptiveExtWrapper // 生成一个AdaptiveExtWrapper类型的instance,并为该instance依赖注入,这里的instance // 没有什么好注入的 instance = injectExtension((T) wrapperClass.getConstructor(type). newInstance(instance)); } } return instance; } }
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException { // 删去无关代码 // 判断是不是Wrapper类型 else if (isWrapperClass(clazz)) { Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } // 是的话,会用HashSet记录下它,这说明wrapper类能够配置多个,后面分析多个的状况 wrappers.add(clazz); } }
// 这里判断是Wrapper类的逻辑很简单,若是该clazz里面有type类型的构造参数,那么它就是,不然会抛出异常,返回false private boolean isWrapperClass(Class<?> clazz) { try { clazz.getConstructor(type); return true; } catch (NoSuchMethodException e) { return false; } }
观看下图能够发现,最后生成的instance是AdaptiveExtWrapper类型的,它里面有一个DubboAdaptiveExt类型变量,adaptiveExt里面有一个ThriftAdaptiveExt类型的变量,因此最后调用adaptiveExtension.echo("d", url)时的adaptiveExtension是AdaptiveExtWrapper类型的,因此输出结果如上,有了AOP的效果.
刚刚分析的只有一个Wrapper类的状况,如今分析有两个的状况,它的Debug结果以下图,清晰易懂框架
输出结果是: before before2 thrift after2 after
更新后的配置文件: dubbo=com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt cloud=com.alibaba.dubbo.demo.provider.adaptive.impl.SpringCloudAdaptiveExt thrift=com.alibaba.dubbo.demo.provider.adaptive.impl.ThriftAdaptiveExt com.alibaba.dubbo.demo.provider.adaptive.impl.AdaptiveExtWrapper com.alibaba.dubbo.demo.provider.adaptive.impl.AdaptiveExtWrapper2
public class AdaptiveExtWrapper2 implements AdaptiveExt { private AdaptiveExt adaptiveExt; public AdaptiveExtWrapper2(AdaptiveExt adaptiveExt) { this.adaptiveExt = adaptiveExt; } @Override public String echo(String msg, URL url) { // do something,实现了AOP System.out.println("before2"); adaptiveExt.echo(msg, url); System.out.println("after2"); // do something return "wrapper"; } }