dubbo SPI及自适应扩展机制

官网:https://dubbo.apache.org/zh/docs/v2.7/dev/source/adaptive-extension/

1、Java SPI 的使用

2、Dubbo 读取配置文件生成实例,按需加载接口实现类,还增加了 IOC 和 AOP 等特性

3、Dubbo 会为拓展接口生成具有代理功能的代码。然后通过 javassist 或 jdk 编译这段代码,得到 Class 类。Dubbo 不会为没有标注 Adaptive 注解的方法生成代理逻辑。方法代理逻辑会从 URL 中提取目标拓展的名称,因此代码生成逻辑的一个重要的任务是从方法的参数列表或者其他参数中获取 URL 数据

简单介绍了 SPI 机制的原理,本节通过一个示例演示 Java SPI 的使用方法。首先,我们定义一个接口,名称为 Robot。

public interface Robot {
    void sayHello();
}

接下来定义两个实现类,分别为 OptimusPrime 和 Bumblebee。

public class OptimusPrime implements Robot {
    
    @Override
    public void sayHello() {
        System.out.println("Hello, I am Optimus Prime.");
    }
}

public class Bumblebee implements Robot {

    @Override
    public void sayHello() {
        System.out.println("Hello, I am Bumblebee.");
    }
}

接下来 META-INF/services 文件夹下创建一个文件,名称为 Robot 的全限定名 org.apache.spi.Robot。文件内容为实现类的全限定的类名,如下:

org.apache.spi.OptimusPrime
org.apache.spi.Bumblebee

做好所需的准备工作,接下来编写代码进行测试。

public class JavaSPITest {

    @Test
    public void sayHello() throws Exception {
        ServiceLoader<Robot> serviceLoader = ServiceLoader.load(Robot.class);
        System.out.println("Java SPI");
        serviceLoader.forEach(Robot::sayHello);
    }
}

最后来看一下测试结果,如下:

Java SPI
Hello, I am Optimus Prime.
Hello, I am Bumblebee.

 

 在这应该多看官网,写的比较详细。这里写利用javassist生成代码的例子

public class ServiceFactoryBean<T> implements FactoryBean<T> {}
private Class<? extends RorServiceInfoListService> rorService;

    private List<RorServiceInfoListService> list;

    public ServiceFactoryBean(ApplicationContext applicationContext, Class<? extends RorServiceInfoListService> clz) {
        this.rorService = clz;
        Map<String, ? extends RorServiceInfoListService> map = applicationContext.getBeansOfType(clz);
        list = new ArrayList<>(map.values());
    }

    @Override
    public T getObject() throws Exception {
        return get();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

    private T get() {
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                for (RorServiceInfoListService spi : list) {
                    // 第一个参数作为条件选择
                    return method.invoke(spi, args);
                }

                throw new IllegalStateException("no service server can execute! spiList: " + list);
            }
        };
        Object o = null;
        try {
            o = newProxyInstance(Thread.currentThread().getContextClassLoader(), RorServiceInfoListService.class, invocationHandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T)o;
    }

    public Object newProxyInstance(ClassLoader loader, Class<?> interfaceClass, InvocationHandler h) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        // 1.创建代理类:public class NewProxyClass
        CtClass proxy0 = pool.makeClass("Proxy0");
        /* 2.给代理类添加字段:private InvocationHandler h; */
        CtClass handle = pool.get(InvocationHandler.class.getName());
        CtField field = new CtField(handle, "h", proxy0);
        field.setModifiers(AccessFlag.PRIVATE);
        proxy0.addField(field);
        /* 3.添加构造函数:public NewProxyClass(InvocationHandler h) { this.h = h; } */
        CtConstructor ctConstructor = new CtConstructor(new CtClass[] { handle }, proxy0);
        ctConstructor.setBody("{this.h = $1;}"); // $0代表this, $1代表构造函数的第1个参数
        proxy0.addConstructor(ctConstructor);
        /* 4.为代理类添加相应接口方法及实现 */
        pool.insertClassPath(new ClassClassPath(interfaceClass));
        CtClass ctClass = pool.get(interfaceClass.getName());
        // 4.1 为代理类添加接口:public class NewProxyClass implements IHello
        proxy0.addInterface(ctClass);
        // 4.2 为代理类添加相应方法及实现
        CtMethod[] declaredMethods = ctClass.getDeclaredMethods();
        for (int i = 0; i < declaredMethods.length; i++) {
            String methodFieldName = "m" + i; // 新方法名
            // 4.2.1 为代理类添加反射方法字段
            // 如:private static Method m1 = Class.forName("chapter9.javassistproxy3.IHello").getDeclaredMethod("sayHello2", new Class[] { Integer.TYPE });
            /* 构造反射字段声明及赋值语句 */
            String classParamsStr = "new Class[0]";
            if (declaredMethods[i].getParameterTypes().length > 0) {
                for (CtClass clazz : declaredMethods[i].getParameterTypes()) {
                    classParamsStr = ((classParamsStr == "new Class[0]") ? clazz.getName() : classParamsStr + "," + clazz.getName()) + ".class";
                }
                classParamsStr = "new Class[] {" + classParamsStr + "}";
            }
            String methodFieldTpl = "private static java.lang.reflect.Method %s = Class.forName(\"%s\").getDeclaredMethod(\"%s\", %s);";
            String methodFieldBody = String.format(methodFieldTpl, "m" + i, interfaceClass.getName(), declaredMethods[i].getName(), classParamsStr);
            System.out.println(methodFieldBody);
            // 为代理类添加反射方法字段
            CtField methodField = CtField.make(methodFieldBody, proxy0);
            proxy0.addField(methodField);
            /* 4.2.2 为方法添加方法体 */
            /* 构造方法体 */
            String methodBody = "h.invoke($0, " + methodFieldName + ", $args)";
            // 如果有返回类型,则需要转换为相应类型后返回
            if (CtPrimitiveType.voidType != declaredMethods[i].getReturnType()) {
                // 对8个基本类型进行转型
                // 例如:((Integer)this.h.invoke(this, this.m2, new Object[] { paramString, new Boolean(paramBoolean), paramObject })).intValue();
                if (declaredMethods[i].getReturnType() instanceof CtPrimitiveType) {
                    CtPrimitiveType ctPrimitiveType = (CtPrimitiveType) declaredMethods[i].getReturnType();
                    methodBody = "return ((" + ctPrimitiveType.getWrapperName() + ") " + methodBody + ")." + ctPrimitiveType.getGetMethodName() + "()";
                } else {// 对于非基本类型直接转型即可
                    methodBody = "return (" + declaredMethods[i].getReturnType().getName() + ") " + methodBody;
                }
            }
            methodBody += ";";
            /* 为代理类添加方法 */
            CtMethod newMethod = new CtMethod(declaredMethods[i].getReturnType(), declaredMethods[i].getName(),declaredMethods[i].getParameterTypes(), proxy0);
            newMethod.setBody(methodBody);
            proxy0.addMethod(newMethod);
        }
        proxy0.writeFile("D://tmp");
        // 5.生成代理实例. 将入参InvocationHandler h设置到代理类的InvocationHandler h变量
        @SuppressWarnings("unchecked")
        Object proxy = proxy0.toClass().getConstructor(InvocationHandler.class).newInstance(h);
        return proxy;
    }

    public static void main(String[] args) throws Exception{
        ClassPool pool = ClassPool.getDefault();
        // 1.创建代理类:public class NewProxyClass
        CtClass proxy0 = pool.makeClass("Proxy0");
        /* 2.给代理类添加字段:private InvocationHandler h; */
        CtClass handle = pool.get(InvocationHandler.class.getName());
        CtField field = new CtField(handle, "h", proxy0);
        field.setModifiers(AccessFlag.PRIVATE);
        proxy0.addField(field);

        /* 4.为代理类添加相应接口方法及实现 */
        CtClass ctClass = pool.get("com.edu.datacenter.ror.service.RorServiceInfoListService");
        // 4.1 为代理类添加接口:public class NewProxyClass implements IHello
        proxy0.addInterface(ctClass);

        /* 3.添加构造函数:public NewProxyClass(InvocationHandler h) { this.h = h; } */
        CtConstructor ctConstructor = new CtConstructor(new CtClass[] { handle }, proxy0);
        ctConstructor.setBody("{this.h = $1;}"); // $0代表this, $1代表构造函数的第1个参数
        proxy0.addConstructor(ctConstructor);

        // 为代理类添加反射方法字段
        CtField methodField = CtField.make("private static java.lang.reflect.Method m0 = Class.forName(\"com.edu.datacenter.ror.service.RorServiceInfoListService\").getDeclaredMethod(\"getData\", new Class[] {com.edu.datacenter.ror.domain.ServiceCtsInfoListReq.class});", proxy0);
        proxy0.addField(methodField);
        proxy0.writeFile("D://tmp");
    }
    @Bean
    public ServiceFactoryBean getServiceFactoryBean(ApplicationContext applicationContext) {
        return new ServiceFactoryBean(applicationContext, RorServiceInfoListService.class);
    }

    @Bean("serviceProxy")
    public RorServiceInfoListService getProxy(ServiceFactoryBean serviceFactoryBean) throws Exception {
        return (RorServiceInfoListService)serviceFactoryBean.getObject();
    }
    @Autowired
    private RorServiceInfoListService serviceProxy;

执行过程中,idea启动可以正常启动。但是放到测试环境,java -jar **.jar启动失败,报错信息

javassist.NotFoundException:.........................................

经修改为

可以正常启动,并执行代码

这里涉及一个小知识点:

1、BeanFactory与FactoryBean的区别,可以扫一遍

2、各种Ware接口,提供资源用的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值