本文基于dubbo2.7.7
- 讲解如何通过Wrapper类实现对SPI实现类的拦截处理
Wrapper包装类
dubbo中定义了一种方式用于对已有的SPI实现类包装:包装类的构造方法仅有一个参数,且参数类型是SPI接口
通过该方式在SPI实现类方法前后拦截处理,包装类同样需要配置在dubbo的SPI配置文件中才能生效。
例如希望在Dubbo执行依赖注入时,打印日志。
- 新建ExtensionFactoryWrapper
@Slf4j
public class ExtensionFactoryWrapper implements ExtensionFactory {
private ExtensionFactory extensionFactory;
public ExtensionFactoryWrapper(ExtensionFactory extensionFactory) {
this.extensionFactory = extensionFactory;
}
@Override
public <T> T getExtension(Class<T> type, String name) {
log.info("查询依赖:{}", type);
return extensionFactory.getExtension(type, name);
}
}
- 在SPI目录新建名为
ExtensionFactoryWrapper
的配置文件,填写如下内容
- 日志效果如下:
需要注意的是如果一个实现类上标记有@Adaptive
则:- 无法使用Wrapper类包装拦截,不生效.
原因:@Adaptive类
是调用的ExtensionLoader#createAdaptiveExtension
不会执行包装类逻辑, 而普通扩展是执行的ExtensionLoader#createExtension(name)
, 会执行包装类逻辑. - 一个实现类不可能既是
@Adaptive
类,又是包装类,优先判断前者。 - 无法通过扩展名获取扩展实例对象,否则报错找不到指定名称的扩展:
- 无法使用Wrapper类包装拦截,不生效.
源码分析
org.apache.dubbo.common.extension.ExtensionLoader#loadClass
- 在加载spi实现类的过程中会先判断
类是否有@Adaptive
注解。 - 再判断存在
SPI接口的构造方法
, 如果存在则是包装类,两者是互斥的。一个实现类不可能既是@Adaptive
类,又是包装类 - dubbo通过
ConcurrentHashSet
保存包装类,这样也就导致多个包装类之间是没法控制执行顺序. 需要自己扩展 - dubbo 2.7.8开始, 多个包装类支持排序, 需要使用
@Activate
注解的order属性指定顺序
org.apache.dubbo.common.extension.ExtensionLoader#createExtension(String name)
遍历包装类,将instance作为构造参数传递创建信息的instance