jannal(无名小宝)

没有失败,只有缓慢的成功

导航

Dubbo之扩展机制深入分析

dubbo版本

  1. dubbo版本2.6.7

扩展点特性

  1. 自动包装(Wrapper)ExtensionLoader在加载扩展时,如果发现这个扩展类包含其他扩展点作为构造函数的参数,则这个扩展类就会被认为是Wrapper类。例如Protocol接口默认就包含ProtocolFilterWrapperProtocolListenerWrapperQosProtocolWrapper三个增强Wrapper实现类

    //继承Protocol接口,并且构造函数传入Protocol类型(装饰模式,增强实现类),被认定为Wrapper类
    //还有诸如ProtocolListenerWrapper、QosProtocolWrapper的类
    public class ProtocolFilterWrapper implements Protocol {
    
        private final Protocol protocol;
    
        public ProtocolFilterWrapper(Protocol protocol) {
            if (protocol == null) {
                throw new IllegalArgumentException("protocol == null");
            }
            this.protocol = protocol;
        }
    ...省略...
    }
    
  2. 自动加载:如果某个扩展类是另一个扩展类的成员变量,并且拥有setter方法,框架会自动注入对应的扩展实例。如果成员变量是一个接口(可能有多个实现),此时应该注入哪个实现呢?

  3. 自适应适配器:通过@Adaptive动态通过URL中的参数来确定使用哪个实现类。当外部调用Transporter#bind方法时,会动态从传入的URL中提取出key为Constants.SERVER_KEY的值,如果能匹配某个扩展实现类则直接使用。如果不能匹配上,则继续提取Constants.TRANSPORTER_KEY的值,如果还是未匹配上,则抛出异常。即@Adaptive传入多个参数,依次进行实现类的匹配,直到抛出异常。

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface Adaptive {
        String[] value() default {};
    
    }
    @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;
    
    }
    
  4. 自动激活:如果需要多个实现类同时被激活,比如Filter可以有多个同时使用,或者根据条件不同,同时激活多个实现类,可以使用@Activate注解。该注解可以标记对应的扩展点为默认激活状态,还可以通过传入不同的参数,设置扩展点在不同条件下被自动激活

    @Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.CACHE_KEY)
    public class CacheFilter implements Filter{
     
    }
    
  5. dubbo扩展点主要在com.alibaba.dubbo.common.extension包下,结构如下

    com.alibaba.dubbo.common.extension
    .
    ├── Activate.java
    ├── Adaptive.java
    ├── DisableInject.java
    ├── ExtensionFactory.java
    ├── ExtensionLoader.java
    ├── SPI.java
    ├── factory
    │   ├── AdaptiveExtensionFactory.java
    │   └── SpiExtensionFactory.java
    └── support
        └── ActivateComparator.java
    
    com.alibaba.dubbo.config.spring.extension
    .
    └── SpringExtensionFactory.java
    

注解

@SPI

  1. @SPI可以使用在类、接口和枚举上。主要作用就是标记接口是一个Dubbo SPI接口,即一个扩展点,可以有多个实现。value属性表示接口的默认实现类对应的Key(在配置文件中)

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    public @interface SPI {
    
        /**
         * default extension name
         */
        String value() default "";
    
    }
    

@Adaptive

  1. @Adaptive可以标记在类、接口、枚举和方法上。如果标记在接口方法上,则可以通过参数动态获得实现类。在第一次getExtension时,会自动生成和编译一个动态的Xxx$Adaptive类,从而达到动态实现类的效果

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface Adaptive {
        String[] value() default {};
    }
    
  2. @Adaptive:该注解可以注解在两个地方

    • 实现类上:例如AdaptiveExtensionFactory(该类不是工厂类,有特殊的逻辑) AdaptiveCompiler(实际上也是工厂类,但是不能靠动态生成,否则会形成死循环),ExtensionLoader需要依赖他们工作,所以得使用此方式

    • 接口的方法上:会动态生成相应的动态类(实际上是一个工厂类,工厂设计模式),例如Protocol$Adapter。ExtensionLoader根据接口定义动态的生成适配器代码,并实例化这个生成的动态类。被@Adaptive注解的方法会生成具体的方法实现。没有注解的方法生成的实现都是抛UnsupportedOperationException。被注解的方法在生成的动态类中,会根据url里的参数信息,来决定实际调用哪个扩展。

@Activate

  1. @Activate可以标记在类、接口、枚举、方法上。主要用于有多个扩展点实现类同时被激活、根据不同的条件激活不同的实现类

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface Activate {
    
        //url分组匹配则激活,如果没有设置则不过滤
        String[] group() default {};
        //url包含指定的key则激活,没有设置则不过滤
        String[] value() default {};
    		//哪些扩展点在当前扩展点之前
        String[] before() default {};
    		//哪些扩展点在当前扩展点之后
        String[] after() default {};
    		//排序
        int order() default 0;
    }
    

ExtensionLoader

  1. ExtensionLoader没有提供public的构造方法,通过静态方法getExtensionLoader获取ExtensionLoader实例。从源码可以看出,类型必须是接口,而且接口必须通过@SPI修饰。每一个扩展点都会对应一个ExtensionLoader

    private ExtensionLoader(Class<?> type) {
        //扩展点接口类型
        this.type = type;
        //非ExtensionFactory类型返回的是一个AdaptiveExtensionFactory
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
    
    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 interface!");
        }
        //接口是否有@SPI注解
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        //如果缓存中不存在,则创建一个新的实例
        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;
    }
    

getExtension

  1. getExtension(String name):根据名称返回一个扩展点实现类,是整个扩展类加载器(ExtensionLoader)最为核心的方法。

    • 从指定目录中(META-INF/dubbo/internal/ META-INF/service/ META-INF/dubbo/)加载所有扩展实现类并缓存(仅仅缓存class对象)
    • 根据传入的名称初始化扩展实现类的实例,并缓存
    • 遍历扩展实现类的所有方法
      • 查找public setter方法(参数仅仅为1),自动注入扩展实现类实例
      • 查找包含与扩展点类型相同的构造函数的Wrapper类,注入扩展实现类实例,并初始化Wrapper类。使用@DisableInject注解修饰的方法不注入,返回Wrapper类实例
    • 如果不存在Wrapper类,返回扩展实现类实例,如果存在返回Wrapper类实例
  2. 主要流程

    getExtension主要流程

  3. 源码流程大致

    getExtension(String name) 如果缓存中存在则读取,否则创建
      => createExtension(name) 创建
        => getExtensionClasses().get(name) 从配置目录加载配置并创建扩展实现类的Class
           => injectExtension(instance) # 注入当前实例依赖的其他扩展点实例
             => injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))实例化wrapper并注入扩展实现类
    
  4. getExtension:判断缓存中是否存在,如果不存在则创建

    public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        //如果为true则调用默认的扩展实现
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        //判断缓存中是否存在
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
    
  5. createExtension:从配置文件中加载配置创建Class并缓存

    private T createExtension(String name) {
        //从配置文件中加载配置Class实例
        Class<?> clazz = getExtensionClasses().get(name);
        //如果找不到则抛出异常
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            //检查是否依赖其他扩展类,如果依赖其他扩展实现类则注入
            injectExtension(instance);
            //创建Wrapper实例,构造注入依赖的类
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }
    
    
  6. getExtensionClasses:从目录中加载配置信息,通过Class.forName创建Class,并保存在缓存中。如果实现类的构造方法是扩展点接口类型,则表示实现类是一个增强包装类(Wrapper)类,将Wrapper类保存到Set中。为什么Wrapper不指定顺序呢?:第一Class的加载顺序不确定,第二Wrapper主要用于增强处理,顺序没有影响。所以在自己实现Wrapper时一定要注意必须与顺序无关

    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;
    }
    
    // synchronized in getExtensionClasses
    private Map<String, Class<?>> loadExtensionClasses() {
        //检查是否有@SPI注解
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if ((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<?>>();
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }
    
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
        String fileName = dir + type.getName();
        try {
            Enumeration<java.net.URL> urls;
            ClassLoader classLoader = findClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }
    
    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
            try {
                String line;
                //每次处理一行
                while ((line = reader.readLine()) != null) {
                    //#号以后的为注释
                    final int ci = line.indexOf('#');
                    //注释去掉
                    if (ci >= 0) line = line.substring(0, ci);
                    line = line.trim();
                    if (line.length() > 0) {
                        try {
                            String name = null;
                            //=号之前的为扩展名字,后面的为扩展类实现的全限定名
                            int i = line.indexOf('=');
                            if (i > 0) {
                                name = line.substring(0, i).trim();
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0) {
                                //加载扩展类的实现
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable t) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                            exceptions.put(line, e);
                        }
                    }
                }
            } finally {
                reader.close();
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }
    
    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error when load extension class(interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + "is not subtype of interface.");
        }
        //如果实现类是@Adaptive类型的,会赋值给cachedAdaptiveClass,这个用来存放被@Adaptive注解的实现类
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            if (cachedAdaptiveClass == null) {
                cachedAdaptiveClass = clazz;
            } else if (!cachedAdaptiveClass.equals(clazz)) {
                throw new IllegalStateException("More than 1 adaptive class found: "
                        + cachedAdaptiveClass.getClass().getName()
                        + ", " + clazz.getClass().getName());
            }
        } else if (isWrapperClass(clazz)) {
            //构造方法参数是扩展点类型的,就是一个Wrapper类
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                //cachedWrapperClasses用来存放当前扩展点实现类中的包装类
              	//因为class的加载顺序是未知的,所以使用Set保存,即应当确保wrapper的实现与顺序无关
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else {
            clazz.getConstructor();
            if (name == null || name.length() == 0) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }
            String[] names = NAME_SEPARATOR.split(name);
            if (names != null && names.length > 0) {
                Activate activate = clazz.getAnnotation(Activate.class);
                if (activate != null) {
                    cachedActivates.put(names[0], activate);
                }
                for (String n : names) {
                    if (!cachedNames.containsKey(clazz)) {
                        cachedNames.put(clazz, n);
                    }
                    Class<?> c = extensionClasses.get(n);
                    if (c == null) {
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                    }
                }
            }
        }
    }
    
    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(type);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }
    
  7. injectExtension:扩展点注入,通过反射获取类的所有方法,遍历setter方法,并得到参数类型。通过ExtensionFactory寻找参数类型相同的扩展类实例,如果找到就通过反射注入。

    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                    //public setter 并且只有一个参数
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        /**
                         * Check {@link DisableInject} to see if we need auto injection for this property
                         */
                        if (method.getAnnotation(DisableInject.class) != null) {
                            continue;
                        }
                        //获取当前实例setter方法的参数
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                            //获取小写开头的名称,setUserInterface 变为userInterface
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            //参数类型如果与扩展点匹配,则调用setter方法注入
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
                                //setter方法注入
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }
    

getAdaptiveExtension

  1. getAdaptiveExtension:获取自适应扩展类,在Dubbo中每一个扩展接口都有一个对应的适配器类Xxx$Adaptive(动态生成的)

    • 从配置中加载配置信息
    • 如果实现扩展类被@Adaptive修饰,则直接使用此实现类,只能有一个实现类被@Adaptive修饰。如果没有被@Adaptive修饰,则自动生成接口$Adaptive形式的类源码,获取类加载器和编译器,编译生成的源码
    • 注入其他扩展类实现
    • 返回对应的自适应实例
  2. 主要流程

    getAdaptiveExtension主要流程

  3. 源码主要逻辑

    getAdaptiveExtension()
      => getAdaptiveExtensionClass 加载所有实现类,如果实现类有被标为@Adaptive的则返回,否则生成【接口$Adaptive】类
        =>injectExtension(instance) 注入实现类或者生成的类
    
  4. 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;
    }
    
    
  5. createAdaptiveExtension:创建自适应实现类

    private T createAdaptiveExtension() {
        try {
            //(T) getAdaptiveExtensionClass().newInstance()类似cn.jannal.spi.UserInterface$Adaptive
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
    
  6. getAdaptiveExtensionClass:获取自适应实现类,如果实现类中没有标记@Adaptive注解的,就生成一个【接口名$Adaptive】的类

    private Class<?> getAdaptiveExtensionClass() {
        //加载所有实现,如果有@Adaptive类型,则会赋值为cachedAdaptiveClass属性缓存起来
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        //如果没有找到@Adaptive修饰的实现类,则自动生成一个
        //生成的类名称类似cn.jannal.spi.UserInterface$Adaptive
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
    
  7. createAdaptiveExtensionClass:组装自适应类的源代码,并编译。组装与编译在后面详细介绍

    private Class<?> createAdaptiveExtensionClass() {
        //组装自适应扩展点类的源代码
        String code = createAdaptiveExtensionClassCode();
        //使用AppClassloader加载
        ClassLoader classLoader = findClassLoader();
        //获取编译器,默认使用javassist
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        //编译源码为Class对象
        return compiler.compile(code, classLoader);
    }
    
  8. injectExtension:注入依赖的扩展点实现,上面已经分析过

生成源代码逻辑

  1. 源代码

    @SPI("userImpl")
    public interface UserInterface {
        //指定默认实现
        @Adaptive({"userImpl"})
        public void run(URL url);
    }
    
  2. 组装后的代码,根据url中的参数获取扩展名字,如果url中没有就使用默认的扩展名,然后根据扩展名去获取具体的实现

    package cn.jannal.spi;
    
    import com.alibaba.dubbo.common.extension.ExtensionLoader;
    
    public class UserInterface$Adaptive implements cn.jannal.spi.UserInterface {
        public void run(com.alibaba.dubbo.common.URL arg0) {
            if (arg0 == null) {
                throw new IllegalArgumentException("url == null");
            }
    
            com.alibaba.dubbo.common.URL url = arg0;
            String extName = url.getParameter("userImpl", "userImpl");
    
            if (extName == null) {
                throw new IllegalStateException(
                    "Fail to get extension(cn.jannal.spi.UserInterface) name from url(" +
                    url.toString() + ") use keys([userImpl])");
            }
    
            cn.jannal.spi.UserInterface extension = (cn.jannal.spi.UserInterface) ExtensionLoader
            		.getExtensionLoader(cn.jannal.spi.UserInterface.class)
            		.getExtension(extName);
            extension.run(arg0);
        }
    }
    
    如果 @Adaptive({"userImpl"})没有指定默认值,比如
    @Adaptive
    public void run(URL url);  
    
    则生成的代码如下,即实现的名称为user.interface
    com.alibaba.dubbo.common.URL url = arg0;
    String extName = url.getParameter("user.interface", "userImpl");
    
  3. 如果一个接口上既有@SPI("userImpl")注解,又有@Adaptive("userImpl2")注解,则最终生成的代码是url.getParameter("userImpl2", "userImpl")。即优先通过@Adaptive("userImpl2")传入的key去找默认实现类,如果没找到,则通过@SPI("userImpl")中的key去查找。如果@SPI注解没有默认值,则把类名转换为key再去查找

  4. 源码生成主要逻辑

    • 校验:接口的所有方法必须有一个方法由@Adaptive注解修饰

    • 生成package(与接口同一个报名)、import(导入ExtensionLoader类)、类名(UserInterface$Adaptive)。其他类调用全部使用全限定名,这样就不需import了

    • 遍历接口所有方法,如果方法没有@Adaptive修饰,则默认抛出UnsupportedOperationException。生成参数校验信息

    • 生成默认实现的名称:如果@Adaptive没有指定默认值,获取接口名的SimpleName,不断查找大写字母,并通过.分隔,得到默认的实现类名。比如接口UserInterface会转换为user.interface

    • 生成获取扩展点名称的代码:根据@Adaptive中配置的key值生成。比如

      1. @Adaptive({"userImpl"}) 生成
      String extName = url.getParameter("userImpl", "userImpl");
      
      2. @Adaptive({"protocol"}) 生成
      String extName = url.getProtocol();
      
    • 生成获取扩展实现类的代码

      ExtensionLoader
              		.getExtensionLoader(cn.jannal.spi.UserInterface.class)
              		.getExtension(extName);
      

编译源代码

  1. 编译源代码生成一个Class。Compiler也是一个SPI接口,@Adaptive注解修饰AdaptiveCompiler,表示AdaptiveCompiler就是编译器的默认实现类,不需要再自动生成(每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive注释的,那么dubbo会动态生成一个自适应实现类(接口名称$Adaptive)

  2. 继承实现图

    Compiler继承图

  3. AdaptiveCompiler:有@Adaptive注解,说明此类是默认实现,与AdaptiveExtensionFactory作用相似,都是为了管理具体的实现。

    //表示默认实现是javassist
    @SPI("javassist")
    public interface Compiler {
        Class<?> compile(String code, ClassLoader classLoader);
    }
    
    @Adaptive
    public class AdaptiveCompiler implements Compiler {
    
        private static volatile String DEFAULT_COMPILER;
    
        //在ApplicationConfig中设置默认编译器,即通过标签<dubbo:application compiler="jdk">
        public static void setDefaultCompiler(String compiler) {
            DEFAULT_COMPILER = compiler;
        }
    
        @Override
        public Class<?> compile(String code, ClassLoader classLoader) {
            Compiler compiler;
            ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
            String name = DEFAULT_COMPILER; // copy reference
            if (name != null && name.length() > 0) {
                compiler = loader.getExtension(name);
            } else {
                compiler = loader.getDefaultExtension();
            }
            return compiler.compile(code, classLoader);
        }
    
    }
    
  4. AbstractCompiler封装一些通用的校验

    • 正则匹配包名和类名,并拼写出类的全限定名称
    • 尝试通过Class.forName加载类,如果已经存在,则无需再次编译。如果不捕获ClassNotFoundException异常,并调用子类的doCompile方法实现源代码编译

getActivateExtension

  1. getActivateExtension:获取自动激活的扩展类,根据不同的条件同时激活多个扩展普通实现类
  • 遍历@Activate注解集合,根据传入URL匹配条件(group和name等)得到所有符合条件的扩展实现类。如果url参数重传入-default,则都不被激活。如果传入的扩展名以-开头,则也不被激活
  • 根据@Activate配置的before、after、order等参数进行排序
  • 遍历所有自定义的扩展类名称,更具用户URL配置的顺序,调整扩展点激活顺序。
  1. 主要流程

  2. 案例

    
    @SPI("AImpl")
    public interface AInterface {
        public void println(String info);
    }
    @Activate(value = {"valueA"}, group = {"group1"})
    public class AInterfaceImpl implements AInterface {
        @Override
        public void println(String info) {
            System.out.println("B:" + info);
        }
    }
    @Activate(value = {"valueB"}, group = {"group1"})
    public class BInterfaceImpl implements AInterface {
        @Override
        public void println(String info) {
            System.out.println("B:" + info);
        }
    }
    创建文件
    src/main/resources/META-INF/dubbo/internal/cn.jannal.spi.activate.AInterface
    AImpl=cn.jannal.spi.activate.AInterfaceImpl
    BImpl=cn.jannal.spi.activate.BInterfaceImpl  
     
    public class Main {
        @Test
        public void testActivate() {
            ExtensionLoader<AInterface> extensionLoader = ExtensionLoader.getExtensionLoader(AInterface.class);
            URL url = URL.valueOf("test://localhost/test");
            url = url.addParameter(Constants.GROUP_KEY, "group1");
            url = url.addParameter("ext", "valueB");
            //url  url中的key  匹配的组名称
            //test://localhost/test?ext=valueB&group=group1
            List<AInterface> interfaces = extensionLoader.getActivateExtension(url, "ext", "group1");
            //[cn.jannal.spi.activate.BInterfaceImpl@1f89ab83]
            System.out.println(interfaces);
            //B:jannal
            for (AInterface aInterface : interfaces) {
                aInterface.println("jannal");
            }
        }
    }  
    
  3. 源码分析

    public List<T> getActivateExtension(URL url, String key, String group) {
        String value = url.getParameter(key);
        return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
    }
    
    public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<T>();
        List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        //-default
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            getExtensionClasses();
            //遍历缓存中所有标记@Activate的实现类
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                //如果group为null返回true
                if (isMatchGroup(group, activate.group())) {
                    T ext = getExtension(name);
                    //排除指定的names扩展,name是配置文件扩展的key,names是url中指定key的values
                    // test://localhost/test?ext=valueB&group=group1
                    //启动name是BImpl(配置文件实现类的key),names是valueB(接口实现Activate中的value)
                    if (!names.contains(name)
                            && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                            && isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        List<T> usrs = new ArrayList<T>();
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
                    && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
                if (Constants.DEFAULT_KEY.equals(name)) {
                    if (!usrs.isEmpty()) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        if (!usrs.isEmpty()) {
            exts.addAll(usrs);
        }
        return exts;
    }
    
    
    private boolean isMatchGroup(String group, String[] groups) {
        if (group == null || group.length() == 0) {
            return true;
        }
        if (groups != null && groups.length > 0) {
            for (String g : groups) {
                if (group.equals(g)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    private boolean isActive(Activate activate, URL url) {
        String[] keys = activate.value();
        //如果Active注解的value没有配置,表示不需要条件都可以使用
        if (keys.length == 0) {
            return true;
        }
        for (String key : keys) {
            for (Map.Entry<String, String> entry : url.getParameters().entrySet()) {
                String k = entry.getKey();
                String v = entry.getValue();
                //判断url中的key是否与active中value的值一致
                if ((k.equals(key) || k.endsWith("." + key))
                        && ConfigUtils.isNotEmpty(v)) {
                    return true;
                }
            }
        }
        return false;
    } 
    
    

ExtensionFactory

  1. ExtensionFactory 主要用于加载扩展的实现。本身也通过@SPI修饰

    @SPI
    public interface ExtensionFactory {
        <T> T getExtension(Class<T> type, String name);
    }
    
  2. ExtensionFactory 有三个实现类,不同的实现可以以不同的方式来完成扩展点实现的加载

  3. AdaptiveExtensionFactory@Adaptive注解注释,意味着它就是ExtensionFactory对应的自适应扩展实现。因为每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive注释的,那么dubbo会动态生成一个自适应实现类(接口名称$Adaptive)

    @Adaptive
    public class AdaptiveExtensionFactory implements ExtensionFactory {
    
        private final List<ExtensionFactory> factories;
    
        public AdaptiveExtensionFactory() {
            ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
            List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
            //遍历所有支持的扩展并保存
            for (String name : loader.getSupportedExtensions()) {
                list.add(loader.getExtension(name));
            }
            factories = Collections.unmodifiableList(list);
        }
    
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            //遍历所有的ExtensionFactory,一旦获取到实例即返回
            for (ExtensionFactory factory : factories) {
                T extension = factory.getExtension(type, name);
                if (extension != null) {
                    return extension;
                }
            }
            return null;
        }
    
    }
    
  4. SpiExtensionFactory:判断是否是接口,接口是否被@SPI注解修饰。如果包含,返回自适应实现类(默认类名为接口名$Adaptive

    public class SpiExtensionFactory implements ExtensionFactory {
    
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            //判断是接口并且存在@SPI注解
            if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
                //获得扩展加载器
                ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
                if (!loader.getSupportedExtensions().isEmpty()) {
                    //返回适配器类的对象
                    return loader.getAdaptiveExtension();
                }
            }
            return null;
        }
    
    }
    

总结

  1. 每一个扩展点都会对应一个ExtensionLoader实例,扩展类型必须是接口而且必须使用@SPI修饰
  2. @Adaptive注解要么注释在扩展点@SPI的方法上,要么注释在其实现类的类定义上。在实现类上定义表示显示指定自适应实现类,否则生成一个【接口名$Adaptive】 的实现类
  3. 如果@Adaptive注解注释在@SPI接口的方法上,没有标记的方法自动生成的实现中默认为注解的方法抛异常
  4. 每个扩展点可以有多个可自动激活的扩展点实现(使用@Activate注解)
  5. 如果扩展点有多个Wrapper,那么最终其执行的顺序不确定(内部使用ConcurrentHashSet存储)

posted on 2021-12-25 22:26  jannal  阅读(74)  评论(0)    收藏  举报