美文网首页dubbo
dubbo之Protocol获取适应扩展过程分析

dubbo之Protocol获取适应扩展过程分析

作者: 晴天哥_王志 | 来源:发表于2019-10-11 19:11 被阅读0次

    开篇

     这篇文章尝试分析Protocol的getAdaptiveExtension过程,和dubbo之ExtensionFactory获取适应扩展过程分析不一样的过程在于ExtensionFactory的扩展类是定义的AdaptiveExtensionFactory,而Protocol的适应扩展是动态生成的。

     所以重点关注下Protocol$Adaptive的动态生成过程,文中会有动态生成后的源码。

    引用例子

    说明:

    • ExtensionLoader的使用分两步走,先getExtensionLoader后getAdaptiveExtension。
    • getExtensionLoader返回对应类的ExtensionLoader。
    • getAdaptiveExtension返回对应类的AdaptiveExtension。
    • Protocol会返回Protocol$Adaptive的扩展类.
    public class ServiceConfig<T> extends AbstractServiceConfig {
        private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
    }
    

    ExtensionLoader介绍

    • 核心部分可以参考dubbo之ExtensionFactory获取适应扩展过程分析的ExtensionLoader介绍。
    • Protocol对应的ExtensionLoader的objectFactory为AdaptiveExtensionFactory。
    • 非ExtensionFactory的ExtensionLoader的objectFactory都是AdaptiveExtensionFactory。
    public class ExtensionLoader<T> {
    
        private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
        private static final String SERVICES_DIRECTORY = "META-INF/services/";
        private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
        private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
        private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
        private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
        private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
        private final Class<?> type;
        private final ExtensionFactory objectFactory;
        private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
        private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
        private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
        private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
        private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
        private volatile Class<?> cachedAdaptiveClass = null;
        private String cachedDefaultName;
        private volatile Throwable createAdaptiveInstanceError;
        private Set<Class<?>> cachedWrapperClasses;
        private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();
    
        private ExtensionLoader(Class<?> type) {
            this.type = type;
            objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
        }
    
        @SuppressWarnings("unchecked")
        public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
            if (type == null) {
                throw new IllegalArgumentException("Extension type == null");
            }
            if (!type.isInterface()) {
                throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
            }
            if (!withExtensionAnnotation(type)) {
                throw new IllegalArgumentException("Extension type (" + type +
                        ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
            }
    
            ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
            if (loader == null) {
                EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
                loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
            }
            return loader;
        }
    }
    
    Protocol对应ExtensionLoader

    createAdaptiveExtension

    • 按照getAdaptiveExtension => createAdaptiveExtension => getAdaptiveExtensionClass => createAdaptiveExtensionClass流程创建AdaptiveExtensionClass。
    • new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate()负责生成Protocol$Adaptive的源码。
    • compiler.compile(code, classLoader)负责生成Protocol$Adaptive的对象。
    public class ExtensionLoader<T> {
    
        public T getAdaptiveExtension() {
            Object instance = cachedAdaptiveInstance.get();
            if (instance == null) {
                if (createAdaptiveInstanceError != null) {
                    throw new IllegalStateException("Failed to create adaptive instance: " +
                            createAdaptiveInstanceError.toString(),
                            createAdaptiveInstanceError);
                }
    
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {
                            instance = createAdaptiveExtension();
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            createAdaptiveInstanceError = t;
                            throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                        }
                    }
                }
            }
    
            return (T) instance;
        }
    
    
        private T createAdaptiveExtension() {
            try {
                return injectExtension((T) getAdaptiveExtensionClass().newInstance());
            } catch (Exception e) {
                throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
            }
        }
    
        private Class<?> getAdaptiveExtensionClass() {
            getExtensionClasses();
            if (cachedAdaptiveClass != null) {
                return cachedAdaptiveClass;
            }
            return cachedAdaptiveClass = createAdaptiveExtensionClass();
        }
    
        private Class<?> createAdaptiveExtensionClass() {
            String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
            ClassLoader classLoader = findClassLoader();
            org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
            return compiler.compile(code, classLoader);
        }
    }
    

    AdaptiveClassCodeGenerator

    说明:

    • generate()方法是生成目标类的主干方法,其主要分为如下几个步骤:
    • 生成package信息。
    • 生成import信息,只导入了ExtensionLoader类,其余的类都通过全限定名的方式来使用。
    • 生成类声明信息。
    • 生成各个方法的实现。
    public class AdaptiveClassCodeGenerator {
    
        public AdaptiveClassCodeGenerator(Class<?> type, String defaultExtName) {
            this.type = type;
            this.defaultExtName = defaultExtName;
        }
    
        public String generate() {
            // no need to generate adaptive class since there's no adaptive method found.
            if (!hasAdaptiveMethod()) {
                throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
            }
    
            StringBuilder code = new StringBuilder();
            // 生成package信息
            code.append(generatePackageInfo());
            // 生成import信息,这里只导入了ExtensionLoader类,其余的类都通过全限定名的方式来使用
            code.append(generateImports());
            // 生成类声明信息
            code.append(generateClassDeclaration());
            // 为各个方法生成实现方法信息
            Method[] methods = type.getMethods();
            for (Method method : methods) {
                code.append(generateMethod(method));
            }
            code.append("}");
    
            if (logger.isDebugEnabled()) {
                logger.debug(code.toString());
            }
            return code.toString();
        }
    }
    

    Protocol$Adaptive

    说明:

    • Protocol本身通过SPI注解。
    • 通过@Adaptive注解的方法在AdaptiveClassCodeGenerator的generate()重新生成源码。
    • 没有通过@Adaptive注解的方法的方法体内会抛异常。
    • 在Protocol$Adaptive的export和refer方法通过ExtensionLoader.getExtensionLoader().getExtension()动态获取扩展。
    • 根据URL动态获取扩展名,String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol())。
    package org.apache.dubbo.rpc;
    
    import org.apache.dubbo.common.URL;
    import org.apache.dubbo.common.extension.Adaptive;
    import org.apache.dubbo.common.extension.SPI;
    
    @SPI("dubbo")
    public interface Protocol {
    
        int getDefaultPort();
    
        @Adaptive
        <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
    
        @Adaptive
        <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
    
        void destroy();
    }
    
    package org.apache.dubbo.rpc;
    import org.apache.dubbo.common.extension.ExtensionLoader;
    
    public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    
        public void destroy()  {
            throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
        }
    
        public int getDefaultPort()  {
            throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
        }
    
        public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
            if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
            
            if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
    
            org.apache.dubbo.common.URL url = arg0.getUrl();
            String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
            if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
            
            org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
            
            return extension.export(arg0);
        }   
    
        public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
            if (arg1 == null) throw new IllegalArgumentException("url == null");
            
            org.apache.dubbo.common.URL url = arg1;
            String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
    
            if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
            org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
    
            return extension.refer(arg0, arg1);
        }
    }
    

    相关文章

      网友评论

        本文标题:dubbo之Protocol获取适应扩展过程分析

        本文链接:https://www.haomeiwen.com/subject/qoxxmctx.html