栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

dubbo 的SPI机制Adaptive适配

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

dubbo 的SPI机制Adaptive适配

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 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> getExtensionClasses() {
        Map> 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注解时候在所有扩展点中优先级最高
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/332444.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号