• dubbo AdaptiveExtension


    AdaptiveExtension
    自适应Extension,作者其实在使用Extension方和Extension之间插入AdaptiveExtension用来自适应,也可以说是适配。
    所以,我们发现,这里其实有三种,
    1,一种是自动生成的Adaptive根据url参数来选择具体实现;
    2,一种是自己实现一个Adaptive,写自己的逻辑选择具体实现,比如AdaptiveExtensionFactory,Compiler。这种都是在ExtensionLoader中需要使用,一般是不会这么做的。
    3,还有一种没有Adaptive,实现一个adapter,比如TelnetHandler。这种因为不能根据url参数来决定使用哪一个实现。
    从结构上看AdaptiveExtension是很重要的角色,我们配置了一些插件,但是具体使用哪一个如果用硬编码自然是不可能的,而这种自适应的方式得益于dubbo的状态数据信息都可以通过URL来获取,被叫做以URL为总线的模式。而自适应即是根据这些信息来决定调用哪一个插件的实现。
     
    ExtensionLoader是插件机制的核心类:
    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    // 获得AdaptiveExtension入口
    public T getAdaptiveExtension() {
            // cachedAdaptiveInstance缓存
            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;
        }
        
         private T createAdaptiveExtension() {
            try {
                return injectExtension((T) getAdaptiveExtensionClass().newInstance());
            } catch (Exception e) {
                throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
            }
        }
        
        private Class<?> getAdaptiveExtensionClass() {
            getExtensionClasses();
            if (cachedAdaptiveClass != null) {
                return cachedAdaptiveClass;
            }
            // 依然没有cachedAdaptiveClass 说明没有配置@Adaptive 那就自动生成一个
            return cachedAdaptiveClass = createAdaptiveExtensionClass();
        }
        
           private Class<?> createAdaptiveExtensionClass() {
             // 组装java代码
            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 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;
        }
        
        private Map<String, Class<?>> loadExtensionClasses() {
            final SPI defaultAnnotation = type.getAnnotation(SPI.class);
            if(defaultAnnotation != null) {
                String value = defaultAnnotation.value();
                if(value != null && (value = value.trim()).length() > 0) {
                    String[] names = NAME_SEPARATOR.split(value);
                    if(names.length > 1) {
                        throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                                + ": " + Arrays.toString(names));
                    }
                    if(names.length == 1) cachedDefaultName = names[0];
                }
            }
            
            Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
            loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
            loadFile(extensionClasses, DUBBO_DIRECTORY);
            loadFile(extensionClasses, SERVICES_DIRECTORY);
            return extensionClasses;
        }
        

    以下方法都会触发loadFile,这个方法就会读取文件,解析出各个插件的class。有@Adaptive注解的会放入赋值给cachedAdaptiveClass。

    下面以Transporter接口为例进行说明自动生成的代码:

    @SPI("netty")
    public interface Transporter {
        @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
        Server bind(URL url, ChannelHandler handler) throws RemotingException;
     
        @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
        Client connect(URL url, ChannelHandler handler) throws RemotingException;
    }

    动态生成类:

    public class Transporter$Adaptive implements Transporter {
     
        public Server bind(URL arg0, ChannelHandler arg1) throws RemotingException {
            URL url = arg0;
            String extName = url.getParameter("server",
                    url.getParameter("transporter", "netty"));
            Transporter extension = (Transporter) ExtensionLoader
                    .getExtensionLoader(Transporter.class).getExtension(extName);
            return extension.bind(arg0, arg1);
        }
     
    }

    Adaptive机制是一个很好的设计,很好的解决多方案实现的适配问题,如果你遇到类似的代码架构的时候,多想一下更加有扩展性的设计。

  • 相关阅读:
    31天重构学习笔记28. 为布尔方法命名
    .NET 技术社区之我见(中文篇)
    31天重构学习笔记26. 避免双重否定
    31天重构学习笔记25. 引入契约式设计
    31天重构学习笔记20. 提取子类
    31天重构学习笔记18. 使用条件判断代替异常
    31天重构学习笔记19. 提取工厂类
    31天重构学习笔记24. 分解复杂判断
    31天重构学习笔记23. 引入参数对象
    31天重构学习笔记17. 提取父类
  • 原文地址:https://www.cnblogs.com/killbug/p/7220586.html
Copyright © 2020-2023  润新知