写在前面
本文需要dubbo SPI的简单基础知识,对dubbo SPI不了解的朋友可以参考dubbo之SPI分析 。
源码!!!。
在dubbo之SPI分析 文章中我们分析了SPI机制,其中有种SPI是一个Wrapper类的情况,本文一起来看下Wrapper的使用,Wapper在dubbo中的作用类似于spring 中AOP,实现扩展类调用拦截的功能,现在考虑这样的一个场景,对于某个扩展类的调用,我们想要做以下的几件事:
1:统计调用时长。
2:记录调用日志。
想要满足这个需求,我们就可以通过Wrapper类来实现,分别对应4个类,如下:
BusinessTopInterface:SPI接口类。
MyConcreteBusinessTopInterface:目标扩展类。
CalWasteTimeWapper:统计调用耗时的Wapper类。
RecordInvokeLogWapper:记录调用日志的Wapper类。
类之间的结构关系如下图最终调用
:
下面我们就开始吧!
1:实例
1.1:定义扩展类接口
import com.alibaba.dubbo.common.extension.SPI;@SPI
public interface BusinessTopInterface {void sayHi();
}
1.2:定义扩展类
public class MyConcreteBusinessTopInterface implements BusinessTopInterface {@Overridepublic void sayHi() {System.out.println("MyConcreteBusinessTopInterface.sayHi ***111***");}
}
1.3:定义计算耗时Wrapper
public class CalWasteTimeWapper implements BusinessTopInterface {private BusinessTopInterface businessTopInterface;// 注意这里必须有一个接收BusinessTopInterface为唯一参数的构造函数,这样才会被识别为Wrapper类public CalWasteTimeWapper(BusinessTopInterface businessTopInterfaceIn) {this.businessTopInterface = businessTopInterfaceIn;}@Overridepublic void sayHi() {System.out.println("*** cal waste time begin***");long startTime = System.currentTimeMillis();// 调用被包裹的类,这里是RecordInvokeLogWapperbusinessTopInterface.sayHi();System.out.println("invoke waste time is: " + (System.currentTimeMillis() - startTime));}
}
1.4:记录调用日志Wrapper
public class RecordInvokeLogWapper implements BusinessTopInterface {private BusinessTopInterface businessTopInterface;public RecordInvokeLogWapper(BusinessTopInterface businessTopInterfaceIn) {this.businessTopInterface = businessTopInterfaceIn;}@Overridepublic void sayHi() {System.out.println("record invoke log to database!");// 调用被包装的类,这里是真正的扩展类MyConcreteBusinessTopInterfacethis.businessTopInterface.sayHi();}
}
1.5:配置文件
我这里是dongshi.daddy.wrapper.BusinessTopInterface
:
注意wrapper的顺序,越往下的越先被调用。
myConcreteBusinessTopInterface=dongshi.daddy.wrapper.MyConcreteBusinessTopInterface
recordInvokeLogWapper=dongshi.daddy.wrapper.RecordInvokeLogWapper
calWasteTimeWapper=dongshi.daddy.wrapper.CalWasteTimeWapper
1.6:main
public class WrapperMain {public static void main(String[] args) {BusinessTopInterface myConcreteBusinessTopInterface = ExtensionLoader.getExtensionLoader(BusinessTopInterface.class).getExtension("myConcreteBusinessTopInterface");myConcreteBusinessTopInterface.sayHi();}
}
运行:
*** cal waste time begin***
record invoke log to database!
MyConcreteBusinessTopInterface.sayHi ***111***
invoke waste time is: 2013
1.7:原理分析重要!!!
当我们执行方法getExtension("myConcreteBusinessTopInterface")
时会执行到代码com.alibaba.dubbo.common.extension.ExtensionLoader.createExtension
,源码如下:
class FakeCls {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, clazz.newInstance());instance = (T) EXTENSION_INSTANCES.get(clazz);}injectExtension(instance);Set<Class<?>> wrapperClasses = cachedWrapperClasses;// 2022-01-23 14:45:21if (wrapperClasses != null && !wrapperClasses.isEmpty()) {for (Class<?> wrapperClass : wrapperClasses) {instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));}}return instance;} catch (Throwable t) {throw new IllegalStateException("Extension instance(name: " + name + ", class: " +type + ") could not be instantiated: " + t.getMessage(), t);}}
}
执行到2022-01-23 14:45:21
处时instance
确实是MyConcreteBusinessTopInterface
,但是会被wrapperClasses
进行层层包裹
,如下debug:
执行后最终return的instance
如下:
写在后面
没什么写的,就吟诗一首吧!
古人学问无遗力,少壮工夫老始成。
纸上得来终觉浅,绝知此事要躬行。