dubbo 的SPI机制Adaptive适配

2 篇文章 0 订阅

SPI机制和Adaptive适配机制

Adaptive适配机制

我们可以使用dubbo的SPI机制, 将dubbo中的一些扩展点通过注解改变原有的实现SPI(“dubbo”), 除此之外Adaptive适配机制则可以帮助我们从参数级别对dubbo的扩展点做出改变。

接口

@SPI("dubbo")
public interface AdaptiveExt2 {
    @Adaptive()
    String echo(String msg, URL url);
}

实现类

public class DubboAdaptiveExt2 implements AdaptiveExt2 {
    @Override
    public String echo(String msg, URL url) {
        return "DubboAdaptiveExt2";
    }
}

public class SpringCloudAdaptiveExt2 implements AdaptiveExt2 {
    @Override
    public String echo(String msg, URL url) {
        return "spring cloud";
    }
}

测试

public class Test {

    public static void main(String[] args) {
        ExtensionLoader<AdaptiveExt2> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt2.class);
        AdaptiveExt2 adaptiveExtension = loader.getAdaptiveExtension();
        URL url = URL.valueOf("test://localhost/test");
        System.out.println(adaptiveExtension.echo("d", url));

    }
}

探究

getAdaptiveExtension

     public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
         // 缓存中没有
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {
                            // 创建
                            instance = createAdaptiveExtension();
                            // 设置缓存
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            createAdaptiveInstanceError = t;
                            throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                        }
                    }
                }
            } else {
                throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
            }
        }
		// 返回实例
        return (T) instance;
    }



createAdaptiveExtension

    private T createAdaptiveExtension() {
        try {
            // 主要是 getAdaptiveExtensionClass()
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
       

getAdaptiveExtensionClass

    private Class<?> getAdaptiveExtensionClass() {
        // 得到扩展点的类, 此方法和SPI中加载扩展点信息相同
        getExtensionClasses();
        // cachedAdaptiveClass 在 SPI的分析中介绍过了,在加载扩展点信息时候,如果发现有类上包含Adaptiva注解,则使用 cachedAdaptiveClass 缓存。
        if (cachedAdaptiveClass != null) {
            // 直接返回, 由此可见如果在类上添加Adaptiva注解,则优先使用
            return cachedAdaptiveClass;
        }
        // 扩展点类上都没 Adaptiva注解, 则去使用代理方式生成
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

getExtensionClasses

加载dubbo的扩展信息

    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }

createAdaptiveExtensionClass

创建适配扩展点类, 主要三步

  • 生成类信息,使用String
  • 得到类加载器
  • 编译类
    private Class<?> createAdaptiveExtensionClass() {
        String code = createAdaptiveExtensionClassCode();
        ClassLoader classLoader = findClassLoader();
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

生成类信息

在这里方法中,我们主要观察它生成的类信息

    private String createAdaptiveExtensionClassCode() {        StringBuilder codeBuilder = new StringBuilder();        // 得到类信息        Method[] methods = type.getMethods();        // 是否有适配注解        boolean hasAdaptiveAnnotation = false;        for (Method m : methods) {            if (m.isAnnotationPresent(Adaptive.class)) {                hasAdaptiveAnnotation = true;                break;            }        }        // 没有需要适配注解 直接报错        if (!hasAdaptiveAnnotation)            throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");		// 生成基本包名等信息        codeBuilder.append("package ").append(type.getPackage().getName()).append(";");        codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");        codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {");        		// 遍历所有方法        for (Method method : methods) {            Class<?> rt = method.getReturnType();            Class<?>[] pts = method.getParameterTypes();            Class<?>[] ets = method.getExceptionTypes();			// 拿到方法上的Adaptive注解信息            Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);            StringBuilder code = new StringBuilder(512);            if (adaptiveAnnotation == null) {                code.append("throw new UnsupportedOperationException(\"method ")                        .append(method.toString()).append(" of interface ")                        .append(type.getName()).append(" is not adaptive method!\");");            } else {                // 当前方法上包含 Adaptive 注解 				// 省略多余代码                String[] value = adaptiveAnnotation.value();                // 没有值, 使用类名作为默认值                if (value.length == 0) {                    char[] charArray = type.getSimpleName().toCharArray();                    StringBuilder sb = new StringBuilder(128);                    for (int i = 0; i < charArray.length; i++) {                        if (Character.isUpperCase(charArray[i])) {                            if (i != 0) {                                sb.append(".");                            }                            sb.append(Character.toLowerCase(charArray[i]));                        } else {                            sb.append(charArray[i]);                        }                    }                    value = new String[]{sb.toString()};                } 				// 省略代码				// cachedDefaultName 是SPI注解中的 value, 下面的循环主要是生成了一段代码                // String extName = url.getParameter( key, value );                - key 是方法上 Adaptive 注解的内容,如果没有的话, 使用类名                - value 使用的 defaultExtName (SPI注解的value)值                String defaultExtName = cachedDefaultName;                String getNameCode = null;                for (int i = value.length - 1; i >= 0; --i) {                    if (i == value.length - 1) {                        if (null != defaultExtName) {                            if (!"protocol".equals(value[i]))                                if (hasInvocation)                                    getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);                                else                                    getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);                            else                                getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName);                        } else {                            if (!"protocol".equals(value[i]))                                if (hasInvocation)                                    getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);                                else                                    getNameCode = String.format("url.getParameter(\"%s\")", value[i]);                            else                                getNameCode = "url.getProtocol()";                        }                    } else {                        if (!"protocol".equals(value[i]))                            if (hasInvocation)                                getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);                            else                                getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);                        else                            getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);                    }                }  		// 省略代码        return codeBuilder.toString();    }

createAdaptiveExtensionClassCode 生成的类信息

package com.weimob.spi;import com.alibaba.dubbo.common.extension.ExtensionLoader;public class AdaptiveExt2$Adaptive implements com.weimob.spi.AdaptiveExt2 {	public java.lang.String echo(java.lang.String arg0, com.alibaba.dubbo.common.URL arg1) {		if (arg1 == null) 			throw new IllegalArgumentException("url == null");		com.alibaba.dubbo.common.URL url = arg1;		String extName = url.getParameter("adaptive.ext2", "dubbo");		if(extName == null) 			throw new IllegalStateException("Fail to get extension(com.weimob.spi.AdaptiveExt2) name from url(" + url.toString() + ") use keys([adaptive.ext2])");        // 可以看到这里使用的是SPI的内容,按照扩展类的名称获取扩展点信息        // extName 的来源和SPI注解、Adaptive注解相关		com.weimob.spi.AdaptiveExt2 extension = (com.weimob.spi.AdaptiveExt2)ExtensionLoader.getExtensionLoader(com.weimob.spi.AdaptiveExt2.class).getExtension(extName);		return extension.echo(arg0, arg1);	}}    public String getParameter(String key, String defaultValue) {        // 去获取key对应的value (URL参数是key?value格式)        String value = getParameter(key);        if (value == null || value.length() == 0) {            // value 为空,使用默认值            return defaultValue;        }        return value;    }

得到信息

  • Adaptive适配机制主要功能是得到扩展点的名称
    • 使用 Adaptive 注解的value作为 扩展点名称
      • value为空时候,选择类名为参数,从URL入参中获取
    • 使用 SPI 注解的value作为 扩展点名称的默认名称
      • 无 Adaptive 注解时,或者按照Adaptive 注解获取不到信息时候
  • 扩展点实现类添加Adaptive注解时候在所有扩展点中优先级最高
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值