dubbo源码阅读-dubbo SPI实现原理(五)

说明

链接

dubboSPI扩展点

项目结构

 

 

SPI注解

@SPI

/**
 * 标识一个接口是否是@SPI接口
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {

    /**
     * SPI扩展的缺省默认值
     */
    String value() default "";

}

如:

@SPI("dubbo")
public interface Protocol {
    // ... 省略代码
}

@Adaptive

可以标记在类上 也可以标记在方法上

标记在类上:表示是我们手动实现装饰类 只能有一个 具体可以看<1>例子

标记在方法上:会通过javasist动态生成一个类 对于方法的实现会根据参数传过来的key动态获取url 具体可以看<1>例子

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
    /**
     * Decide which target extension to be injected. The name of the target extension is decided by the parameter passed
     * in the URL, and the parameter names are given by this method.
     * <p>
     * If the specified parameters are not found from {@link URL}, then the default extension will be used for
     * dependency injection (specified in its interface's {@link SPI}).
     * <p>
     * For examples, given <code>String[] {"key1", "key2"}</code>:
     * <ol>
     * <li>find parameter 'key1' in URL, use its value as the extension's name</li>
     * <li>try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL</li>
     * <li>use default extension if 'key2' doesn't appear either</li>
     * <li>otherwise, throw {@link IllegalStateException}</li>
     * </ol>
     * If default extension's name is not give on interface's {@link SPI}, then a name is generated from interface's
     * class name with the rule: divide classname from capital char into several parts, and separate the parts with
     * dot '.', for example: for {@code com.alibaba.dubbo.xxx.YyyInvokerWrapper}, its default name is
     * <code>String[] {"yyy.invoker.wrapper"}</code>. This name will be used to search for parameter from URL.
     *
     * @return parameter key names in URL
     *  用于打在方法上动态javasist动态生成的装饰类 方法 url.getParameter(key)就是这里配置 
     */
    String[] value() default {};

}

@Activate

打了此类的注解将会自动加载

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain

 @Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
    /**
     * 激活当前扩展类的条件之一, 该group参数将会与ExtensionLoader#getActivateExtension方法传入的gruop参数进行匹配
     * @return 要匹配的组名
     * @see ExtensionLoader#getActivateExtension(URL, String, String)
     */
    String[] group() default {};

    /**
     当URL中出现该value值时激活扩展类
     例如:@Activate("cache, validation")注释在一个接口上,当URL中有cache或者validation参数时激活
     * @return URL对应的参数的keys
     * @see ExtensionLoader#getActivateExtension(URL, String)
     * @see ExtensionLoader#getActivateExtension(URL, String, String)
     */
    String[] value() default {};

    /**
     * 排序信息,可选
     * @return 在当前扩展类执行之前的扩展类
     */
    String[] before() default {};

    /**
     * 排序信息,可选
     * @return 在当前扩展类执行之后的扩展类
     */
    String[] after() default {};


    /**
     * 当前类执行的权重,越小越先执行
     */
    int order() default 0;
}

 如dubbo几个Filter的实现

/**
 * LimitInvokerFilter
 * 当group group 同时配置了actives=*就会返回此过滤器 methodParameter含有actives
 */
@Activate(group = Constants.CONSUMER, value = Constants.ACTIVES_KEY)
public class ActiveLimitFilter implements Filter {

 

/**
 * CacheFilter
 * group为consumer或者provider 同时 含有cache=*的配置的时候 返回此过滤器 methodParametr含有activies
 */
@Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.CACHE_KEY)
public class CacheFilter implements Filter {

}

getExtension(name)加载过程

//adaptive javasist生成例子  
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) 
//<2>getExtensionLoader <18>getExtension
ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);

 

getAdaptiveExtension加载过程

 /**
     * 获取Protocol Spi实现对象
     * <2>getExtensionLoader   <5>getAdaptiveExtension
     */
    private static final Protocol protocol = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

 

 

getActivateExtension(url,key,group)加载过程

 com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper#buildInvokerChain

 //<16>获取激活对象 参数如:key service.filter gruop=provider
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);

 

ExtensionLoader

静态变量

    //==============================静态变量
    //[1]扫描服务实现的文件存放
    private static final String SERVICES_DIRECTORY = "META-INF/services/";
    //[2]扫描服务实现的文件存放
    private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
    //[3]dubbo内置的spi服务实现
    private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
    //[5]spi配置分割符号,分割 比如 key=fullClassName1,fullClassName2
    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
    /***
     * [6]每个class类都会创建一个对应ExtensionLoader ExtnsionLoader实例不用每次都加载
     * 如我们常常在dubbo看到这样的代码
     *  private static final Protocol protocol =(Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
     */
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
    /**
     * [7]各个class和实现的定义 比如 key
     * key:com.alibaba.dubbo.rpc.Protocol vaue=实例对象
     */
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();

成员变量

  // =============================成员变量

    /***
     *[8] ExtensionLoader.getExtensionLoader(Protocol.class)
     * 存的就是Protocol.class
     */
    private final Class<?> type;

    //[9]创建对象工厂 默认2种实现SPIExtensionFactory SpringExtensionFactory 一个是扫描文件加载 一个在spring容器查找
    private final ExtensionFactory objectFactory;

    /**
     * [10]spi配置  key:class value:name
     * 比如 spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
     * key:com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory value:spi
     */
    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();

    //[11]Holder内部维护了map 与cachedNames相反 key=spi配置key  vlaue:spi配置类的class
    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();

    //[12]当前类的适配类集合如Filter的实现ExceptonFilter  CacheFitler等
    //key等于@Activate配置的value value等于注解信息
    private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
    /**
     * [12]存储当前接口class实现类的对象
     * 每次实例化都会存入缓存 避免重复创建 下次直接从缓存拿
     * ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("injvm")
     * ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo")
     */
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    //Spi接口打上了@Adaptive的类的实例
    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    //Spi接口打上了@Adaptive的类的class
    private volatile Class<?> cachedAdaptiveClass = null;
    //spi接口配置的 value 如:@SPI("jvalidation")
    private String cachedDefaultName;
    private volatile Throwable createAdaptiveInstanceError;
    /**
     * 拓展 Wrapper 实现类集合
     * <p>
     * 带唯一参数为拓展接口的构造方法的实现类
     * <p>
     * 通过 {@link #loadExtensionClasses} 加载
     */
    private Set<Class<?>> cachedWrapperClasses;

    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();

<2>getExtensionLoader

静态方法

   @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        //如果没有传class抛出错误
        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!");
        }
        //尝试从缓存获取 ExtentionLoader静态变量[6]
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            //第一次获取会new一个并存入缓存<3>
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

<3>ExtensionLoader(Class<T> type)

  private ExtensionLoader(Class<?> type) {
        //存入成语变量[8]
        this.type = type;
        //type实例的创建工厂 可以发现也是一个SPI扩展 如果不是ExtensionFactory.class才加载工厂 用于创建type实例 工厂定义请看<4>  getAdaptiveExtension请看<5>
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

<5>getAdaptiveExtension

    @SuppressWarnings("unchecked")
    public T getAdaptiveExtension() {
        /**
         * 从成员变量获取适配类 避免重复获取
         * 分为类上打:@Adaptive 打上Lee@Adaptive的对象
         * 和方法打:@Adaptive 方法打就是javasisit动态生成的装饰类对象
         */
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            //未加载成功的原因是发生了异常。为null表示未加载 非null表示加载过程中出现异常 直接抛出
            if (createAdaptiveInstanceError == null) {
                //加锁 避免重复加载
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    //二次判断避免锁穿透
                    if (instance == null) {
                        try {
                            //<6>创建适配器类对象
                            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;
    }

 <6>createAdaptiveExtension

private T createAdaptiveExtension() {
        try {
            //获取SPI适配类 <7>getAdaptiveExtensionClass 先获得对象 再 <15>injectExtension完成依赖注入 
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

 

<7>getAdaptiveExtensionClass

private Class<?> getAdaptiveExtensionClass() {
        //<8>加载SPI配置信息
        getExtensionClasses();
        //如果当前spi接口含有@Adaptive的实现类 则直接返回
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        //<13>根据javaSisit动态生成适配class
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

<8>getExtensionClasses

 private Map<String, Class<?>> getExtensionClasses() {
        //从缓存获取当前ExtensionLoader的所有spi配置映射  key为spi文件配置的key value为 spi文件配置的class全名称
        //避免重复加载spi文件
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                //避免锁穿透
                classes = cachedClasses.get();
                if (classes == null) {
                    //<9>加载spi文件
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }

<9>loadExtensionClasses

 private Map<String, Class<?>> loadExtensionClasses() {
        //获得SPI注解 type对应成员变量[8]
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            //获得spi配置的value 如Protocol 配置的"dubbo"
            String value = defaultAnnotation.value();
            if ((value = value.trim()).length() > 0) {
                //防止,号分割配置多个 对应静态变量[5]
                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));
                }
                //设置到 对应成员变量 [12] +3
                if (names.length == 1) cachedDefaultName = names[0];
            }
        }

        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        //在一下几个目录扫描SPI配置 所以们自定义SPI配置可以定义在以下几个目录
        //<10>加载dubbo 内置spi META-INF/dubbo/internal/
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        //<10>META-INF/dubbo/
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        //<10>META-INF/services/
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }

<10>loadDirectory

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
        //spi文件必须为 目录+SPI注解的fullName
        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();
                    //<11>这里最终会将SPI扫描 并将class封装到extensionClasses key为SPI文件key value为Spi文件配置的CLASS
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

<11>loadResource

  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;
                //逐行遍历如:adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
                while ((line = reader.readLine()) != null) {
                    //如果有#分割符号 则去掉#分隔符后之后数据
                    //如adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory#method
                    //则会读取adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
                    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) {
                                //获取key
                                name = line.substring(0, i).trim();
                                //获取value
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0) {
                                //<12>加载class 第一个参数为集合  第二个参数为反射创建 第三个参数为key
                                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);
        }
    }

<12>loadClass

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
         //判断spi配置 是不是当前SPI接口的实现类
        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.");
        }
        //判断class是否打了@Adaptive注解 如果打了那么就是手动装饰类
        //并存入成员变量[15]
        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());
            }
            //当前类是否含有构造函数 并且为当前SPI接口 装饰者 具体可以参考
        } else if (isWrapperClass(clazz)) {
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                //对应成员变量18
                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);
                //是否是打了@Activate注解
                if (activate != null) {
                    //如果打了则存入成员变量[12]
                    cachedActivates.put(names[0], activate);
                }
                for (String n : names) {
                    if (!cachedNames.containsKey(clazz)) {
                        //存入成员变量[10]
                        cachedNames.put(clazz, n);
                    }
                    //存入extensionClasses  key为name value为class 也就是成员变量[11]cachedClasses
                    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());
                    }
                }
            }
        }
    }

<13>createAdaptiveExtensionClass

    private Class<?> createAdaptiveExtensionClass() {
        //<14>获得动态生成的java字符串
        String code = createAdaptiveExtensionClassCode();
        ClassLoader classLoader = findClassLoader();
        //编译成class
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

<14>createAdaptiveExtensionClassCode

 private String createAdaptiveExtensionClassCode() {
        StringBuilder codeBuilder = new StringBuilder();
        //反射获得SPI接口的所有方法
        Method[] methods = type.getMethods();
        //判断是否有含有打上@Adaptive的方法
        boolean hasAdaptiveAnnotation = false;
        for (Method m : methods) {
            if (m.isAnnotationPresent(Adaptive.class)) {
                hasAdaptiveAnnotation = true;
                break;
            }
        }
        // no need to generate adaptive class since there's no adaptive method found.
        //如果SPI接口没有打上了@Adaptive的方法 则抛出异常
        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 {
                int urlTypeIndex = -1;

                //获取方法的ULR类型参数所在索引
                for (int i = 0; i < pts.length; ++i) {
                    if (pts[i].equals(URL.class)) {
                        urlTypeIndex = i;
                        break;
                    }
                }
                //如果含有URL参数则生成非空判断
                // found parameter in URL type
                if (urlTypeIndex != -1) {
                    // Null Point check 如:if (arg1 == null) throw new IllegalArgumentException("url == null");
                    String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
                            urlTypeIndex);
                    code.append(s);

                    //如:com.alibaba.dubbo.common.URL url = arg1;
                    s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex);
                    code.append(s);
                }
                // did not find parameter in URL type
                else {
                    String attribMethod = null;

                    // find URL getter method
                    LBL_PTS:
                    for (int i = 0; i < pts.length; ++i) {
                        Method[] ms = pts[i].getMethods();
                        for (Method m : ms) {
                            String name = m.getName();
                            if ((name.startsWith("get") || name.length() > 3)
                                    && Modifier.isPublic(m.getModifiers())
                                    && !Modifier.isStatic(m.getModifiers())
                                    && m.getParameterTypes().length == 0
                                    && m.getReturnType() == URL.class) {
                                urlTypeIndex = i;
                                attribMethod = name;
                                break LBL_PTS;
                            }
                        }
                    }
                    if (attribMethod == null) {
                        throw new IllegalStateException("fail to create adaptive class for interface " + type.getName()
                                + ": not found url parameter or url attribute in parameters of method " + method.getName());
                    }

                    // Null point check
                    String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
                            urlTypeIndex, pts[urlTypeIndex].getName());
                    code.append(s);
                    s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
                            urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);
                    code.append(s);

                    s = String.format("%s url = arg%d.%s();", URL.class.getName(), urlTypeIndex, attribMethod);
                    code.append(s);
                }

                String[] value = adaptiveAnnotation.value();
                // value is not set, use the value generated from class name as the key
                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()};
                }

                boolean hasInvocation = false;
                for (int i = 0; i < pts.length; ++i) {
                    if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) {
                        // Null Point check
                        String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"invocation == null\");", i);
                        code.append(s);
                        s = String.format("\nString methodName = arg%d.getMethodName();", i);
                        code.append(s);
                        hasInvocation = true;
                        break;
                    }
                }

                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);
                    }
                }
                code.append("\nString extName = ").append(getNameCode).append(";");
                // check extName == null?
                String s = String.format("\nif(extName == null) " +
                                "throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\");",
                        type.getName(), Arrays.toString(value));
                code.append(s);

                s = String.format("\n%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",
                        type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
                code.append(s);

                // return statement
                if (!rt.equals(void.class)) {
                    code.append("\nreturn ");
                }

                s = String.format("extension.%s(", method.getName());
                code.append(s);
                for (int i = 0; i < pts.length; i++) {
                    if (i != 0)
                        code.append(", ");
                    code.append("arg").append(i);
                }
                code.append(");");
            }

            codeBuilder.append("\npublic ").append(rt.getCanonicalName()).append(" ").append(method.getName()).append("(");
            for (int i = 0; i < pts.length; i++) {
                if (i > 0) {
                    codeBuilder.append(", ");
                }
                codeBuilder.append(pts[i].getCanonicalName());
                codeBuilder.append(" ");
                codeBuilder.append("arg").append(i);
            }
            codeBuilder.append(")");
            if (ets.length > 0) {
                codeBuilder.append(" throws ");
                for (int i = 0; i < ets.length; i++) {
                    if (i > 0) {
                        codeBuilder.append(", ");
                    }
                    codeBuilder.append(ets[i].getCanonicalName());
                }
            }
            codeBuilder.append(" {");
            codeBuilder.append(code.toString());
            codeBuilder.append("\n}");
        }
        codeBuilder.append("\n}");
        if (logger.isDebugEnabled()) {
            logger.debug(codeBuilder.toString());
        }
        return codeBuilder.toString();
    }
View Code

<15>injectExtension

   /* 完成动态注入
     * @param instance
     * @return
     */
    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {

                //获得SPI类所有包含一个参数的Set方法 同时是公共的
                for (Method method : instance.getClass().getMethods()) {
                    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
                         *
                         * 如果打了DisableInject注解则不注入
                         */
                        if (method.getAnnotation(DisableInject.class) != null) {
                            continue;
                        }
                        //获取
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                            //剔除set 比如setDefaultCompiler 取出defaultCompiler
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            //对象工厂获取实例
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
//反射set实现注入 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; }

 <16>getActivateExtension

 public List<T> getActivateExtension(URL url, String key, String group) {
        //从url获取指定key的参数 比如provider传入的filter就是server.filter
        String value = url.getParameter(key);
        //<17>传入url 指定key获取的value 多个,号隔开
        return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
    }

<17>getActivateExtension

  public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<T>();
        //url配置对应key的value
        List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        //加载默认的 是否包含指定key value=-default的配置 -default忽略默认配置
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            //<8>加载当前SPI接口的Class
            getExtensionClasses();
            //<12>处初始化
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                //2个group做匹配 映证了@Activate的说法
                if (isMatchGroup(group, activate.group())) {
                    //根据spikey获取对应class实例
                    T ext = getExtension(name);
                    //url传入的key不包含激活类配置
                    if (!names.contains(name)
                            //因为-name表示移除 同时未移除
                            && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                            //如果配置了value 则必须在url判断是否有配置value激活
                            //比如配置@Activate("limit") n那么url必须传入limit=*
                            && isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }
            //根据@Activate配置的sort排序
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        List<T> usrs = new ArrayList<T>();
        //加载用户要激活的
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            //不加载-name的 因为表示剔除 上面默认配置也不会加载
            if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
                    && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
                /// 将配置的自定义在自动激活的拓展对象们前面。例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。i
                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;
    }

<18>getExtension

    @SuppressWarnings("unchecked")
    public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        //如果配置的true则返回默认配置key即@SPI("dubbo")则返回dubbo
        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) {
                    //<19>获得指定name的SPI实现类
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

<19>createExtension

   @SuppressWarnings("unchecked")
    private T createExtension(String name) {
        //根据key获取SPI的配置的value 同时内部也是加载<8>
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            //获取对应class 的缓存实例对象
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            //<15>动态注入
            injectExtension(instance);
            //获取wapper代理 <12> 处初始化
            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);
        }
    }

 

<4>ExtensionFactory

类图

 

 

 

接口定义

@SPI
public interface ExtensionFactory {

    /**
     * Get extension.
     *
     * @param type object type.
     * @param name object name.
     * @return object instance.
     */
    <T> T getExtension(Class<T> type, String name);

}

SPI配置

 

 

dubbo-common

resource/com.alibaba.dubbo.common.extension.ExtensionFactory

adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory

SpringExtensionFactory 

 */
public class SpringExtensionFactory implements ExtensionFactory {
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getExtension(Class<T> type, String name) {
        //遍历spring 容器 根据beanName获取
        for (ApplicationContext context : contexts) {
            //如果spring有这个bean直接返回
            if (context.containsBean(name)) {
                Object bean = context.getBean(name);
                if (type.isInstance(bean)) {
                    return (T) bean;
                }
            }
        }

        logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
        //避免传入的是Object直接返回空
        if (Object.class == type) {
            return null;
        }
        //根据根据BeanName未获取到 再根据Type获取
        for (ApplicationContext context : contexts) {
            try {
                return context.getBean(type);
            } catch (NoUniqueBeanDefinitionException multiBeanExe) {
                logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
            } catch (NoSuchBeanDefinitionException noBeanExe) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
                }
            }
        }

        logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");

        return null;
    }
}

 

SpiExtensionFactory

/**
 * SpiExtensionFactory
 */
public class SpiExtensionFactory implements ExtensionFactory {

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        //必须是接口类型 同时打上了@SPI注解
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            //<3>
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            //<6>如果含有SPI注解
            if (!loader.getSupportedExtensions().isEmpty()) 
            {
                //<5>
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }

}

AdaptiveExtensionFactory

/**
 * AdaptiveExtensionFactory
 * 打了@Adaptive注解是一个手动装饰类
 */
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {

        //加载 spi配置的ExtensionFactory配置实现
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        //保存在spi成员变量
        factories = Collections.unmodifiableList(list);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
            //动态适配前面2种工厂 创建对象
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

 

 

 

 

<1>@Adaptive类例子

打在实现类上的实现

spi接口

@SPI
public interface ExtensionFactory {

    /**
     * Get extension.
     *
     * @param type object type.
     * @param name object name.
     * @return object instance.
     */
    <T> T getExtension(Class<T> type, String name);

}

作用就是我们手动生成装饰类而不是利用javasist动态生成

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {

        //加载 spi配置的ExtensionFactory配置实现
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        //保存在spi成员变量
        factories = Collections.unmodifiableList(list);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
            //动态适配前面2种工厂选择其中一个
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

 

打在接口方法上生成的代理

@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 com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.extension.ExtensionLoader;

public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }

    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
        if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
        com.alibaba.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
}

 

@SPI("javassist")
public interface ProxyFactory {

    /**
     * create proxy.
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * create proxy.
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;

    /**
     * create invoker.
     *
     * @param <T>
     * @param proxy
     * @param type
     * @param url
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

 

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.extension.ExtensionLoader;

public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory {
    public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
        if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
        com.alibaba.dubbo.common.URL url = arg0.getUrl();
        String extName = url.getParameter("proxy", "javassist");
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
        com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
        return extension.getProxy(arg0);
    }
    public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws java.lang.Object {
        if (arg2 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg2;
        String extName = url.getParameter("proxy", "javassist");
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
        com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
        return extension.getInvoker(arg0, arg1, arg2);
    }
}

总结

1.dubbo默认会从META-INF/dubbo/internal/  ,META-INF/dubbo/,META-INF/services/ 加载SPI扩展文件

2.SPI扩展文件名字必须为SPI接口全名称

3.dubboSPI注入 会在反射获取SPI实例的set方法 获取方法名字 比如setAppliation 则会在spi和spring容器获取key="application"的spi实例

4.之所以会获取SPI和spring的实例是因为对象工厂的实现AdaptiveExtensionFactory 内部整合了2种容器

posted @ 2020-03-10 09:46  意犹未尽  阅读(353)  评论(0编辑  收藏  举报