dubbo之SPI Wrapper分析

写在前面

本文需要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 {
    @Override
    public 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;
    }

    @Override
    public void sayHi() {
        System.out.println("*** cal waste time begin***");
        long startTime = System.currentTimeMillis();
        // 调用被包裹的类,这里是RecordInvokeLogWapper
        businessTopInterface.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;
    }

    @Override
    public void sayHi() {
        System.out.println("record invoke log to database!");
        // 调用被包装的类,这里是真正的扩展类MyConcreteBusinessTopInterface
        this.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:21
            if (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如下:

在这里插入图片描述

写在后面

没什么写的,就吟诗一首吧!

古人学问无遗力,少壮工夫老始成。
纸上得来终觉浅,绝知此事要躬行。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值