SPI

转载自:https://my.oschina.net/pingpangkuangmo/blog/508963
            http://wely.iteye.com/blog/2304718

 

SPI机制简介

       SPI的全名为ServiceProvider Interface,是JDK内置的一种服务提供发现机制,或者说是为某个接口寻找服务实现的机制,在java.util.ServiceLoader的文档里有比较详细的介绍。
       举个例子来下应用场景,比如有个接口,想运行时动态的给它添加实现,你只需要添加一个实现,然后把新加的实现描述给JDK知道就行(通过改一个文本文件即可),目前Dubbo框架就基于SPI机制提供扩展功能。

       首先通过一张图来看看,用SPI需要遵循哪些规范:
  
      Java SPI约定,当服务的提供者,提供了服务接口的一种实现之后,在META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。

      通过一个简单例子来说明SPI是如何使用的。
      首先定义接口和实现类:

package org.zero.spi;
public interface HelloInterface {
    public void sayHello();
}
package org.zero.spi.impl;
import org.zero.spi.HelloInterface;
public class JavaHello implements HelloInterface {
    @Override
    public void sayHello() {
        System.out.println("Java: Hello World!");
    }
}
package org.zero.spi.impl;
import org.zero.spi.HelloInterface;
public class ScalaHello implements HelloInterface {
    @Override
    public void sayHello() {
        System.out.println("Scala: Hello World!");
    }
}

      然后在resources目录下新建META-INF\services目录,然后添加org.zero.spi.HelloInterface文件,文件内容是:

org.zero.spi.impl.JavaHello
org.zero.spi.impl.ScalaHello

      来整个测试:

package org.zero.spi;
import java.util.ServiceLoader;
public class Test {
    public static void main(String[] args) {
        ServiceLoader<HelloInterface> loaders = ServiceLoader.load(HelloInterface.class);
        for (HelloInterface impl : loaders) {
            impl.sayHello();
        }
    }
}

     运行结果:

Java: Hello World!
Scala: Hello World!

      到此,大致应该知道了SPI怎么用了。
      再来看关键的ServiceLoader类:

public final class ServiceLoader<S>
    implements Iterable<S>
{
    private static final String PREFIX = "META-INF/services/";

    // The class or interface representing the service being loaded
    private final Class<S> service;

    // The class loader used to locate, load, and instantiate providers
    private final ClassLoader loader;

    // The access control context taken when the ServiceLoader is created
    private final AccessControlContext acc;

    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

    // The current lazy-lookup iterator
    private LazyIterator lookupIterator;

      可以看到PREFIX就是指定了要找的那个文件的目录,service是服务接口,loader是类加载器,providers是服务实现类的缓存,lookupIterator是获取服务实现类的迭代器,是 ServiceLoader 的内部类。
      一般来说,文件加载并解析完成之后,得到一系列的接口实现类的完整类名,然后在使用时调用到lookupIterator的next()时实例化,并保存到了providers中。所以,ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类会全部加载并实例化一遍。如果并不想用某些实现类,它也会被加载并实例化。而且获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类。
 


dubbo的扩展机制

      dubbo的扩展机制和java的SPI机制非常相似,但是又增加了如下功能:
      1.可以方便的获取某一个想要的扩展实现,java的SPI机制就没有提供这样的功能;
      2.对于扩展实现IOC依赖注入功能。举例来说明,接口A,实现者A1、A2,接口B,实现者B1、B2,现在实现者A1含有setB()方法,会自动注入一个接口B的实现者,此时注入B1还是B2呢?都不是,而是注入一个动态生成的接口B的实现者B$Adpative,该实现者能够根据参数的不同,自动引用B1或者B2来完成相应的功能;
      3.对扩展采用装饰器模式进行功能增强,类似AOP实现的功能。

dubbo中需要扩展的接口需要使用SPI注解:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
    /**
     * default extension name
     */
    String value() default "";  //默认使用的实现类的名称
}

dubbo实现的类似SPI机制使用的是ExtensionLoader类:

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<Class<?>, ExtensionLoader<?>>();
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();

    // ==============================

    private final Class<?> type;
    private final ExtensionFactory objectFactory;
    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();

    //Map<String, Class<?>> name---> 具体实现类的class
    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();

    private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>(); //Activate注解的类,key是Activate注解的值
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    private volatile Class<?> cachedAdaptiveClass = null;  //Adaptive注解的类,有且仅有一个
    private String cachedDefaultName; 
    private volatile Throwable createAdaptiveInstanceError;

    private Set<Class<?>> cachedWrapperClasses; // 构造函数有接口参数的类

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

可以看出,配置文件的目录有"META-INF/services/"、"META-INF/dubbo/"、"META-INF/dubbo/internal/"。


ExtensionLoader中没有提供public的构造方法,但是提供了一个public static的getExtensionLoader,这个方法就是获取ExtensionLoader实例的工厂方法:

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!");
    }
    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;
}

该方法需要一个Class类型的参数,该参数表示希望加载的扩展点类型,该参数必须是接口,且该接口必须被@SPI注解,否则拒绝处理。检查通过之后首先会检查ExtensionLoader缓存EXTENSION_LOADERS中是否已经存在该扩展对应的ExtensionLoader,如果有则直接返回,否则创建一个新的ExtensionLoader负责加载该扩展实现,同时将其缓存起来。

接下来看下ExtensionLoader的私有构造函数:

    private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

这里设置了一个额外的objectFactory属性,它是一个ExtensionFactory类型,然后通过getAdaptiveExtension方法获取对应的自适应的扩展类型,每个Extension只能有一个@Adaptive注解的自适应实现,如果没有dubbo会动态生成这样的一个类。

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);
}

ExtensionFactory也被@SPI注解注释,dubbo内部提供了两个实现类:SpiExtensionFactory 和 AdaptiveExtensionFactory。默认的ExtensionFactory实现中,AdaptiveExtensionFactotry被@Adaptive注解注释,也就是说它就是ExtensionFactory对应的自适应扩展实现。AdpativeExtensionFactory实现代码:

@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()) {
            // 将所有的ExtensionFactory实现保存起来,不包含Adaptive
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    public <T> T getExtension(Class<T> type, String name) {
        // 依次遍历各个ExtensionFactory实现的getExtension方法,一旦获取到Extension即返回  
        // 如果遍历完所有的ExtensionFactory实现均无法找到Extension,则返回null 
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }
}


来关注几个重要的方法。首先是getAdaptiveExtension():

 

public T getAdaptiveExtension() {
    Object instance = cachedAdaptiveInstance.get();//首先判断是否已经有缓存的实例对象
    if (instance == null) {
        if (createAdaptiveInstanceError == null) {
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        // 没有缓存的实例,创建新的AdaptiveExtension实例  
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        } else {
            throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
        }
    }
    return (T) instance;
}
private T createAdaptiveExtension() {
    try {
        // 先获取AdaptiveExtensionClass,在获取其实例,最后进行注入处理  
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}
private Class<?> getAdaptiveExtensionClass() {
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

getExtensionClasses()方法中会加载当前Extension的所有实现,如果有@Adaptive类型的,则会赋值为cachedAdaptiveClass属性缓存起来,如果没有找到@Adaptive类型实现,则动态创建一个AdaptiveExtensionClass。


getExtensionClassses()以及之后的调用链比较重要,就涉及到了配置文件的加载,getExtensionClassses()会从cachedClasses中去看有没有,没有说明没有加载过配置文件,则去调用loadExtensionClasses()方法:

private Map<String, Class<?>> loadExtensionClasses() {
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if (defaultAnnotation != null) {
        String value = defaultAnnotation.value();
        if (value != null && (value = value.trim()).length() > 0) {
            String[] names = NAME_SEPARATOR.split(value);
            if (names.length > 1) {
                throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                        + ": " + Arrays.toString(names));
            }
            if (names.length == 1) cachedDefaultName = names[0];
        }
    }

    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    loadFile(extensionClasses, DUBBO_DIRECTORY);
    loadFile(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}

SPI接口必须以@SPI声明,如果@SPI上有值则会设置在cachedDefaultName中,接下来就去之间说到的三个目录中读取配置文件, loadFile()方法中最关键的部分如下:

        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) {
            Class<?> clazz = Class.forName(line, true, classLoader);// 加载扩展实现类
            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.");
            }
            if (clazz.isAnnotationPresent(Adaptive.class)) {
                // 判断该实现类是否@Adaptive
                // 是的话放在cachedAdaptiveClass,但不会放入extensionClasses/cachedClasses
                // 只能有一个
                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 { //不是@Adaptive类型  
                try {
                    // 判断是否Wrapper类型,依据是有 type类型为参数的构造函数
                    clazz.getConstructor(type);
                    Set<Class<?>> wrappers = cachedWrapperClasses;
                    if (wrappers == null) {
                        cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                        wrappers = cachedWrapperClasses;
                    }
                    wrappers.add(clazz);
                } catch (NoSuchMethodException e) {
                    clazz.getConstructor();
                    if (name == null || name.length() == 0) {
                        name = findAnnotationName(clazz);
                        if (name == null || name.length() == 0) {
                            if (clazz.getSimpleName().length() > type.getSimpleName().length()
                                    && clazz.getSimpleName().endsWith(type.getSimpleName())) {
                                name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
                            } else {
                                throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
                            }
                        }
                    }
                    String[] names = NAME_SEPARATOR.split(name);
                    if (names != null && names.length > 0) {
                        // 是否@Activate类型 
                        Activate activate = clazz.getAnnotation(Activate.class);
                        if (activate != null) {
                            //放入cachedActivates缓存 
                            cachedActivates.put(names[0], activate);
                        }
                        for (String n : names) {
                            // 放入Extension实现类与名称映射缓存,每个class只对应第一个名称有效
                            if (!cachedNames.containsKey(clazz)) {
                                cachedNames.put(clazz, n);
                            }
                            //放入到cachedClasses,多个name可能对应一个Class
                            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());
                            }
                        }
                    }
                }
            }
        }

执行完成之后,以下几个变量就会被附上值:

  • cachedAdaptiveClass: 当前Extension类型对应的AdaptiveExtension类型(只能一个)
  • cachedWrapperClasses: 当前Extension类型对应的所有Wrapper实现类型(无顺序)
  • cachedActivates : 当前Extension实现自动激活实现缓存
  • cachedNames : 扩展点实现类对应的名称(如配置多个名称则值为第一个)
  • cachedClasses:扩展点的实现类,包括普通类别、@Activate,不包括@Adaptive


OK,完成了getAdaptiveExtensionClass()后继续回到createAdaptiveExtension()方法:

 

private T createAdaptiveExtension() {
    try {
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}
private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            for (Method method : instance.getClass().getMethods()) {
                if (method.getName().startsWith("set")
                        && method.getParameterTypes().length == 1
                        && Modifier.isPublic(method.getModifiers())) {
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        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) {
                            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;
}

这里就是@Adaptive实例根据setter方法对应的参数类型和property名称从ExtensionFactory中查询,如果就进行注入操作。到这里getAdaptiveExtension方法就分析完毕了。

再来看getExtension(String name):

public T getExtension(String name) {
    if (name == null || name.length() == 0)
        throw new IllegalArgumentException("Extension name == null");
    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;
}

先去看cachedInstances有没有,没有的话就createExtension。createExtension()方法中先去EXTENSION_INSTANCES看cachedClasses中的有没有已经被加载了,有的话就不再实例化,然后实例化cachedWrapperClasses中的实现类,这里需要注意的是,遍历cachedWrapperClasses时都是对通过将上一次的结果作为下一个构造函数参数传递进去实例化一个对象的,最后返回出去的是Wrapper类型的实例而不是具体实现类的实例:

// …
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
    for (Class<?> wrapperClass : wrapperClasses) {
        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
    }
}
return instance;


getActivateExtension()方法主要获取当前扩展的所有可自动激活的实现。可根据入参(values)调整指定实现的顺序,在这个方法里面也使用到getExtensionClasses方法中收集的缓存数据。

 

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",则加载所有Activates扩展(names指定的扩展)
    if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
        getExtensionClasses(); // 加载当前Extension所有实现,会获取到当前Extension中所有@Active实现,赋值给cachedActivates变量
        for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { // 遍历当前扩展所有的@Activate扩展
            String name = entry.getKey();
            Activate activate = entry.getValue();
            if (isMatchGroup(group, activate.group())) { // 判断group是否满足,group为null则直接返回true
                T ext = getExtension(name); // 获取扩展示例
                // 排除names指定的扩展;并且如果names中没有指定移除该扩展(-name),且当前url匹配结果显示可激活才进行使用
                if (! names.contains(name)
                        && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                        && isActive(activate, url)) {
                    exts.add(ext);
                }
            }
        }
        Collections.sort(exts, ActivateComparator.COMPARATOR); // 默认排序
    }

    // 对names指定的扩展进行专门的处理
    List<T> usrs = new ArrayList<T>();
    for (int i = 0; i < names.size(); i ++) { // 遍历names指定的扩展名
        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)) { // default表示上面已经加载并且排序的exts,将排在default之前的Activate扩展放置到default组之前,例如:ext1,default,ext2
                if (usrs.size() > 0) { // 如果此时user不为空,则user中存放的是配置在default之前的Activate扩展
                    exts.addAll(0, usrs); // 注意index是0,放在default前面
                    usrs.clear(); // 放到default之前,然后清空
                }
            } else {
                T ext = getExtension(name);
                usrs.add(ext);
            }
        }
    }

    if (usrs.size() > 0) { // 这里留下的都是配置在default之后的
        exts.addAll(usrs); // 添加到default排序之后
    }
    return exts;
}



总结
• 每个ExtensionLoader实例只负责加载一个特定扩展点实现
• 每个扩展点对应最多只有一个ExtensionLoader实例
• 对于每个扩展点实现,最多只会有一个实例
• 一个扩展点实现可以对应多个名称(逗号分隔)
• 对于需要等到运行时才能决定使用哪一个具体实现的扩展点,应获取其自使用扩展点实现(AdaptiveExtension)
• @Adaptive注解要么注释在扩展点@SPI的方法上,要么注释在其实现类的类定义上
• 如果@Adaptive注解注释在@SPI接口的方法上,那么原则上该接口所有方法都应该加@Adaptive注解(自动生成的实现中默认为注解的方法抛异常)
• 每个扩展点最多只能有一个被AdaptiveExtension
• 每个扩展点可以有多个可自动激活的扩展点实现(使用@Activate注解)
• @Adaptive注解注释在@SPI接口的方法上时,如果没有AdaptiveExtension,dubbo会自动生成一个AdaptiveExtension类,类名“接口类名$Adaptive”,该类只会对@Adaptive注释的方法进行扩展,且方法的第一个参数必须是URL类型。方法扩展时,@Adaptive注解没有值时会从URL的parameters中获取名称是接口类小写(HelloInterface为hello.interface)的extension来调用该方法,parameters没有改参数会用cachedDefaultName值;如果有时依据values的顺序优先从parameters获取,注意如果是value值是"protocol"时,会用URL的protocol的值。




 


 


 


 


 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值