简介

SPI全称Service Provider Interface,是Java供给的一套用来被第三方完成或者扩展的,它可以用来启用结构扩展和替换组件。

咱们体系里笼统的各个模块,往往有许多不同的完成计划,比方日志模块、xml解析模块、jdbc模块等计划。面向的目标的设计里,咱们一般引荐模块之间依据接口编程,模块之间不对完成类进行硬编码。一旦代码里涉及详细的完成类,就违反了可拔插的准则,假如需要替换一种完成,就需要修正代码。为了完成在模块安装的时分能不在程序里动态指明,这就需要一种服务发现机制。 Java SPI便是供给这样的一个机制:为某个接口寻觅服务完成的机制。有点相似IOC的思维,便是将安装的操控权移到程序之外,在模块化设计中这个机制特别重要。

Java的SPI机制: ServiceLoader

用法

// java.sql.Driver
// 1.new一个ServiceLoader
ServiceLoader<Driver> drivers = ServiceLoader.load(Driver.class);
Iterator<Driver> iterator = drivers.iterator();
// 2.调用推迟加载器的hashNext
while (iterator.hasNext()) {
 // 3.调用推迟加载器的next
 Driver next = iterator.next();
 System.out.println(next.getClass());
}
​
// result:
class com.mysql.jdbc.Driver
class com.mysql.fabric.jdbc.FabricMySQLDriver
class com.alibaba.druid.proxy.DruidDriver
class com.alibaba.druid.mock.MockDriver

原理

ServiceLoader并不会在load的时分去加载一切 接口对应完成类的文件。而是在履行接口的时分去遍历加载。

ServiceLoader的中心特点

// 接口全限定名的文件的途径前缀
private static final String PREFIX = "META-INF/services/";
​
// 被加载的接口
private final Class<S> service;
​
// 类的加载器
private final ClassLoader loader;
​
// 创立serviceLoader时 访问操控上下文
private final AccessControlContext acc;
​
// 服务缓存池(k-> 类全报名  v-> 完成类信息)
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
​
// 推迟加载的迭代器
private LazyIterator lookupIterator;

LazyIterator的中心特点

// 接口类型
Class<S> service;
// 接的加载器
ClassLoader loader;
// META-INF/services/内装备文件的URL调集
Enumeration<URL> configs = null;
// 需加载的完成类的全包名调集
Iterator<String> pending = null;
// 下一个完成类的全报名,用于迭代器推迟加载的下一个类
String nextName = null;

源码解析

1、load办法

// 1、load办法
public static <S> ServiceLoader<S> load(Class<S> service) {
 // 获取当时线程的类加载器
 ClassLoader cl = Thread.currentThread().getContextClassLoader();
 // 继续调用重载的办法
 return ServiceLoader.load(service, cl);
}
​
// 2、调用重载办法
public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader) {
 // new 一个ServiceLoader目标
 return new ServiceLoader<>(service, loader);
}
​
// 3、new 一个serviceLoader目标
private ServiceLoader(Class<S> svc, ClassLoader cl) {
 // PS:服务接口不能为空
 service = Objects.requireNonNull(svc, "Service interface cannot be null");
 // 指定加载器
 loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
 // 指定下上容器(默以为null)
 acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
 // 改写:1.重置服务缓冲池 2.new一个推迟加载的迭代器
 reload();
}
​
// 4、改写 
public void reload() {
 // 重置服务缓存池
 providers.clear();
 // 构造一个推迟加载的迭代器
 lookupIterator = new LazyIterator(service, loader);
}
​
// 5、new LazyIterator
private LazyIterator(Class<S> service, ClassLoader loader) {
 // 指定接口的类信息
 this.service = service;
 // 指定类加载器
 this.loader = loader;
}

2、获取推迟加载的迭代器

3、调用推迟加载迭代器的hasNext()办法

// 1、调用hasNext()办法
public boolean hasNext() {
  // 默许 acc为null
 if (acc == null) {
  // 履行hasNextService()办法
  return hasNextService();
  } else {
  PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
   public Boolean run() { return hasNextService(); }
   };
  return AccessController.doPrivileged(action, acc);
  }
}
​
// 2、调用hasNextService()办法
private boolean hasNextService() {
 // 默许第一次履行 nextName为null
 if (nextName != null) {
  return true;
  }
 // 默许第一次履行 configs为null, 经过类加载器加载类的全报名,然后获取URL。
 if (configs == null) {
  try {
   // "META-INF/services/" + java.sql.Driver
   // 1.file:/Users/zhouzeng/.m2/repository/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar!/META-INF/services/java.sql.Driver
   // 2.file:/Users/zhouzeng/.m2/repository/com/alibaba/druid/1.0.28/druid-1.0.28.jar!/META-INF/services/java.sql.Driver
   String fullName = PREFIX + service.getName();
   if (loader == null) {
    configs = ClassLoader.getSystemResources(fullName);
    } else {
    configs = loader.getResources(fullName);
    }
   } catch (IOException x) {
   fail(service, "Error locating configuration files", x);
   }
  }
 // 默许第一次履行 pending为null
 while ((pending == null) || !pending.hasNext()) {
  if (!configs.hasMoreElements()) {
   return false;
   }
  // 依据 接口+ URL 解析 
  /**
   * 1.0 = "com.mysql.jdbc.Driver" 1 = "com.mysql.fabric.jdbc.FabricMySQLDriver"
   * 2.0 = "com.alibaba.druid.proxy.DruidDriver" 1 = "com.alibaba.druid.mock.MockDriver"
   **/
  pending = parse(service, configs.nextElement());
  }
 // com.mysql.jdbc.Driver
 nextName = pending.next();
 return true;
}
​

4、next()办法

// 1.履行next办法
public S next() {
 // 默许 acc为null
 if (acc == null) {
  // 调用nexrService()办法
  return nextService();
  } else {
  PrivilegedAction<S> action = new PrivilegedAction<S>() {
   public S run() { return nextService(); }
   };
  return AccessController.doPrivileged(action, acc);
  }
}
​
// 2.履行nextService()办法
private S nextService() {
 // 判别是否还有下一个类需要加载
 if (!hasNextService()) {
  throw new NoSuchElementException(); 
  }
 // 1.com.mysql.jdbc.Driver
 // 2.com.mysql.fabric.jdbc.FabricMySQLDriver
 // 3.com.alibaba.druid.proxy.DruidDriver
 // 4.com.alibaba.druid.mock.MockDriver
 String cn = nextName;
 nextName = null;
 Class<?> c = null;
 try {
  // 生成接口的完成类
  c = Class.forName(cn, false, loader);
  } catch (ClassNotFoundException x) {
  fail(service, "Provider " + cn + " not found");
  }
 // 校验完成类 是不是接口的完成类
 if (!service.isAssignableFrom(c)) {
  fail(service, "Provider " + cn + " not a subtype");
  }
 try {
  // 将完成类的实例,转化为接口类型(类型转化)
  S p = service.cast(c.newInstance());
  // 放到缓存池中
  providers.put(cn, p);
  return p;
  } catch (Throwable x) {
  fail(service, "Provider " + cn + " could not be instantiated", x);
  }
 throw new Error();
}

优缺点

优点:将业务代码和详细完成类解耦,便利扩展。如需增加新逻辑,无需修正主流程,直接在PI装备文件增加完成类的全限定名即可。

缺点:颗粒度不行细,无法精确定位某一个完成类。要履行就履行一切的完成类。

SpringBoot 之SPI机制:SpringFactoriesLoader

使用

1.创立一个enableConfiguration

@Configuration
@EnableConfigurationProperties({MybatisProperties.class})
public class MybatisAutoConfiguration {
  
}

2.在resources下界说META-INF/spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

3.用SpringBoot发动

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    } 
}

在springbot发动时回去加载MybatisAutoConfiguration这个类。

原理

1、在SpringBoot发动时,在refreshContext()时,回去调用@Import的selector。

2、然后履行 AutoConfigurationImportSelector的process()办法 获取对应的configuration的List。

3、由Spring 去加载实例化configuration的装备类。

// 1.SpringBootApplication中的SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};
}
// 2.SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
	Class<?>[] exclude() default {};
	String[] excludeName() default {};
}
// 3.检查 AutoConfigurationImportSelector的selectImports()办法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
  if (!this.isEnabled(annotationMetadata)) {
    return NO_IMPORTS;
  } else {
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
    AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
    // 获取enableautoconfiguration相关的类
    List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
    configurations = this.removeDuplicates(configurations);
    Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
    this.checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = this.filter(configurations, autoConfigurationMetadata);
    this.fireAutoConfigurationImportEvents(configurations, exclusions);
    return StringUtils.toStringArray(configurations);
  }
}
// 4. 履行getCandidateConfigurations()办法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, 
                                                  AnnotationAttributes attributes) {
  // 获取configurations
  List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
    															this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
  Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
  return configurations;
}
// 5. 履行loadFactoryNames()办法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
  // org.springframework.boot.autoconfigure.EnableAutoConfiguration
  String factoryClassName = factoryClass.getName();
  // 加载spring.fatories的装备项,然后获取key为EnableAutoConfiguration的value
  return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

SpringFactoriesLoader的中心特点

// 1.spring 资源加载的默许途径
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 2.缓存池 K为类加载器 HK为接口全包名 HV为完成类
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
// 6.履行loadSpringFactories()办法,依据类加载器,获取META-INF/spring.factories下的装备
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  // 在缓存池中获取,有则直接回来。
  MultiValueMap<String, String> result = cache.get(classLoader);
  if (result != null) {
    return result;
  }
  try {
    // 获取"META-INF/spring.factories"的URL
    Enumeration<URL> urls = (classLoader != null ?
                             classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                             ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
    result = new LinkedMultiValueMap<>();
    while (urls.hasMoreElements()) {
      URL url = urls.nextElement();
      UrlResource resource = new UrlResource(url);
      Properties properties = PropertiesLoaderUtils.loadProperties(resource);
      for (Map.Entry<?, ?> entry : properties.entrySet()) {
        List<String> factoryClassNames = Arrays.asList(
          StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
        result.addAll((String) entry.getKey(), factoryClassNames);
      }
    }
    // 将解析出来的数据放到缓存池中。
    cache.put(classLoader, result);
    return result;
  }
  catch (IOException ex) {
    throw new IllegalArgumentException("Unable to load factories from location [" +
                                       FACTORIES_RESOURCE_LOCATION + "]", ex);
  }
}

Dubbo的SPI机制

用法

代码

// 1.界说接口
@SPI("wechat")
public interface Order {
    /**
     * 付出办法
     *
     * @return 成果
     */
    String way();
}
// 2.接口完成AlipayOrder
public class AlipayOrder implements Order {
    @Override
    public String way() {
        System.out.println("--- 付出宝way() ---");
        return "付出宝付出办法";
    }
}
// 3.接口完成WeChatOrder
public class WeChatOrder implements Order {
    @Override
    public String way() {
        System.out.println("--- 微信way() ---");
        return "微信付出办法";
    }
}

装备

在META-INF/dubbo目录下添加装备文件(com.example.spidemo.dubbo.base.Order)

wechat,wechat2=com.example.spidemo.dubbo.base.impl.WeChatOrder
alipay=com.example.spidemo.dubbo.base.impl.AlipayOrder

测验类

public static void test1() {
  ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
  Order alipay = loader.getExtension("alipay");
  System.out.println(alipay.way());
  //同一个完成类,多个称号,是同一个实例
  Order wechat = loader.getExtension("wechat");
  System.out.println(wechat.way());
  Order wechat2 = loader.getExtension("wechat2");
  System.out.println(wechat2 == wechat);
  /**
   * 成果:
   * --- 付出宝way() ---
   * 付出宝付出办法
   * --- 微信way() ---
   * 微信付出办法
   * true
   */
}
public static void test2() {
  ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
  //验证不指定前缀的情况,这里会报错
  Order alipay = loader.getDefaultExtension();
  System.out.println(alipay.way());
  /**
   * 成果:
   * Exception in thread "main" java.lang.IllegalArgumentException: Extension name == null
   * 	at org.apache.dubbo.common.extension.ExtensionLoader.getExtension(ExtensionLoader.java:340)
   * 	at com.example.spidemo.dubbo.adaptive.DubboSpiTest02.main(DubboSpiTest02.java:14)
   */
}

流程

// 1.构造Order的ExtensionLoader,其中还构造了对应的ExtensionFactory -》AdaptiveExtensionFactory();
1.ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
2.1.loader.getExtension("alipay");
2.2.loader.getDefaultExtension();
2.3.loader.getAdaptiveExtension();
2.4.loader.getActivateExtension(url, "", "online");

ExtensionLoader的中心特点

// 加载文件的途径
// "META-INF/services/"、"META-INF/dubbo/" 、"META-INF/dubbo/internal/"
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/";
// 存储的是 SPI接口类和ExtensionLoader目标的映射联系 缓存池
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
// 存储的是 每个SPI接口的多个完成类和对应实例之间的联系
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
// 接口的类型
private final Class<?> type;
// 获取工厂类,用于获取Spring容器中的Bean
private final ExtensionFactory objectFactory;
// 扩展类和扩展称号映射联系
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
// 扩展称号和扩展类类型映射联系
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
// 扩展称号和主动激活扩展类映射联系
private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
// 扩展称号和扩展类实例映射联系
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
// 自适应扩展类实例缓存
private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
// 自适应扩展类
private volatile Class<?> cachedAdaptiveClass = null;
// 默许的服务供给者的称号
private String cachedDefaultName;
// 包装扩展类调集
private Set<Class<?>> cachedWrapperClasses;

源码解析

ExtensionLoader.getExtensionLoader(Order.class);

流程

Dubbo的SPI机制简介共享

代码解析
// 1.ExtensionLoader.getExtensionLoader源码
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  	// 接口类不能为空
    if (type == null) {
        throw new IllegalArgumentException("Extension type == null");
    }
  	// 有必要是接口
    if (!type.isInterface()) {
        throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
    }
  	// 有必要有@SPI注解
    if (!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException("Extension type (" + type +
                ") is not an extension, because it is NOT annotated with @" 
                                           + SPI.class.getSimpleName() + "!");
    }
  	// 在ExtensionLoader缓存池中获取
    ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    if (loader == null) {
      	// 不存在,则new一个对应SPI的ExtensionLoader(***要点***)
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
      	// 添加到缓存池中
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}
// withExtensionAnnotation办法
private static <T> boolean withExtensionAnnotation(Class<T> type) {
    return type.isAnnotationPresent(SPI.class);
}
// 2.new ExtensionLoader<T>(type)源码解析
private ExtensionLoader(Class<?> type) {
  // 设置SPI的类型
  this.type = type;
  // type是不是为ExtensionFactory?是则回来null, 不是则去获取一个ExtensionFactory的ExtensionLoader的适配器扩展器
  objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
// 3.getAdaptiveExtension()办法
public T getAdaptiveExtension() {
  	// 从当时的SPI的ExtensionLoader中的缓存池中获取适配器
    Object instance = cachedAdaptiveInstance.get();
  	// dubbo check
    if (instance == null) {
        if (createAdaptiveInstanceError == null) {
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                      	// 创立一个SPI的适配器扩展器,并放入的缓存池中(***要点***)
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        } else {
            throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
        }
    }
    return (T) instance;
}
// 4.createAdaptiveExtension()办法
private T createAdaptiveExtension() {
    try {
      	// 获取适配器扩展器,然后在获取实例目标,再注入特点(injectExtension,IOC的完成)
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}
// 5.获取扩展器的适配器
private Class<?> getAdaptiveExtensionClass() {
    // 1.加载默许的扩展器的称号
    // 2.加载各个目录下的SPI的服务供给者:
    // 2.1.假如是适配器,则加载到适配器的缓存中(PS:在办法上加@Adaptive,不会被加载到适配器缓存池中)
    // 2.2.假如是装修器,则加载到装修器的缓存中
    // 2.3.加载主动激活的缓存中
    // 2.4 加载到缓存cachedNames中(k->class,v->name)
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
  	// 假如没有扩展器的适配器,则去动态创立一个(比较复杂)
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
// 6. loadExtensionClasses()办法
private Map<String, Class<?>> loadExtensionClasses() {
  // 1.获取SPI的value获取默许姓名 加载默许的扩展器的称号
  cacheDefaultExtensionName();
  // 2. 加载各个目录下的SPI的装备文件
  // 2.1.假如是适配器,则加载到适配器的缓存中
 	// 2.2.假如是装修器,则加载到装修器的缓存中
  // 2.3.把name加载主动激活的缓存中,把name到SPI的name缓存池,把SPI name和类的对应联系缓存到
  Map<String, Class<?>> extensionClasses = new HashMap<>();
  loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
  loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
  loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
  loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  return extensionClasses;
}
// 7.loadDirectory加载目录下的类
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
  String fileName = dir + type;
  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 occurred when loading extension class (interface: " +
                 type + ", description file: " + fileName + ").", t);
  }
}
// 8.加载资源loadResource
// 9.加载类
    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 occurred when loading extension class (interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + " is not subtype of interface.");
        }
      	// 假如是适配器,则加载到适配器的缓存中
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz);
        // 假如是装修器,则加载到装修器的缓存中
        } else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
        } else {
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                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 (ArrayUtils.isNotEmpty(names)) {
              	// 把name加载主动激活的缓存中
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                  	// 把name到SPI的name缓存池,把SPI name和类的对应联系缓存到
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, n);
                }
            }
        }
    }

其实咱们不难发现上述仅仅加载的咱们SPI对应ExtensionLoader的ExtensionFactory的getAdaptiveExtension()

–> AdaptiveExtensionFactory

1.常用办法extensionLoader.getExtension(“alipay”);

流程

Dubbo的SPI机制简介共享

代码解析
// 1.获取Order的称号为"alipay"的SPI
public T getExtension(String name) {
  // 校验
  if (StringUtils.isEmpty(name)) {
    throw new IllegalArgumentException("Extension name == null");
  }
  // 假如姓名为true,则回来默许的SPI
  if ("true".equals(name)) {
    return getDefaultExtension();
  }
  // 从cachedInstances缓存池中获取"alipay"的完成类。
  final Holder<Object> holder = getOrCreateHolder(name);
  Object instance = holder.get();
  // dubbo check
  if (instance == null) {
    synchronized (holder) {
      instance = holder.get();
      if (instance == null) {
        // 创立一个完成类的实例Bean,并设置到缓存池中。
        instance = createExtension(name);
        holder.set(instance);
      }
    }
  }
  return (T) instance;
}
// 2.创立Extension createExtension(name);
private T createExtension(String name) {
  // 1.加载默许的扩展器的称号
  // 2.加载各个目录下的SPI的服务供给者:
  // 2.1.假如是适配器,则加载到适配器的缓存中(PS:在办法上加@Adaptive,不会被加载到适配器缓存池中)
  // 2.2.假如是装修器,则加载到装修器的缓存中
  // 2.3.加载主动激活的缓存中
  // 2.4 加载到缓存cachedNames中(k->class,v->name)
  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);
    }
    // 注入数据
    injectExtension(instance);
    // 判别是否有装修器,有则遍历装修器
    Set<Class<?>> wrapperClasses = cachedWrapperClasses;
    if (CollectionUtils.isNotEmpty(wrapperClasses)) {
      // 一套又一套
      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 + ") couldn't be instantiated: " + t.getMessage(), t);
  }
}
// 3.注入特点
private T injectExtension(T instance) {
  try {
    if (objectFactory != null) {
      for (Method method : instance.getClass().getMethods()) {
        // 只能注入setter办法的特点。
        if (isSetter(method)) {
          /**
           * Check {@link DisableInject} to see if we need auto injection for this property
           */
          if (method.getAnnotation(DisableInject.class) != null) {
            continue;
          }
          Class<?> pt = method.getParameterTypes()[0];
          if (ReflectUtils.isPrimitives(pt)) {
            continue;
          }
          try {
            String property = getSetterProperty(method);
            // 调用AdaptiveExtensionFactory的 办法获取特点值。
            Object object = objectFactory.getExtension(pt, property);
            if (object != null) {
              method.invoke(instance, object);
            }
          } catch (Exception e) {
            logger.error("Failed to inject via method " + method.getName()
                         + " of interface " + type.getName() + ": " + e.getMessage(), e);
          }
        }
      }
    }
  } catch (Exception e) {
    logger.error(e.getMessage(), e);
  }
  return instance;
}
// 3.1. 调用AdaptiveExtensionFactory的getExtension(pt, property)
public <T> T getExtension(Class<T> type, String name) {
  // 循环遍历SpiExtensionFactory和SpringExtensionFactory。
  for (ExtensionFactory factory : factories) {
    T extension = factory.getExtension(type, name);
    if (extension != null) {
      return extension;
    }
  }
  return null;
}

2.常用办法loader.getAdaptiveExtension();

流程

Dubbo的SPI机制简介共享

代码解析
// loader.getAdaptiveExtension() ,整体逻辑和getExtension("alipay") 差不多。
// 唯一有差异的是
// getAdaptiveExtension()是createAdaptiveExtension()
// getExtension("alipay")是createExtension("alipay")
public T getAdaptiveExtension() {
  // 从适配器缓存池中拿,假如没有则用createAdaptiveExtension()生成一个,再设置到缓存池中。
  Object instance = cachedAdaptiveInstance.get();
  if (instance == null) {
    if (createAdaptiveInstanceError == null) {
      synchronized (cachedAdaptiveInstance) {
        instance = cachedAdaptiveInstance.get();
        if (instance == null) {
          try {
            // 生成适配器类的实例目标instance,并设置到缓存中
            instance = createAdaptiveExtension();
            cachedAdaptiveInstance.set(instance);
          } catch (Throwable t) {
            createAdaptiveInstanceError = t;
            throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
          }
        }
      }
    } else {
      throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
    }
  }
  return (T) instance;
}
// 2.createAdaptiveExtension()
private T createAdaptiveExtension() {
  try {
    return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  } catch (Exception e) {
    throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
  }
}
// 3.getAdaptiveExtensionClass()
private Class<?> getAdaptiveExtensionClass() {
  // 1.加载默许的扩展器的称号
  // 2.加载各个目录下的SPI的服务供给者:
  // 2.1.假如是适配器,则加载到适配器的缓存中(PS:在办法上加@Adaptive,不会被加载到适配器缓存池中)
  // 2.2.假如是装修器,则加载到装修器的缓存中
  // 2.3.加载主动激活的缓存中
  // 2.4 加载到缓存cachedNames中(k->class,v->name)
  getExtensionClasses();
  // 假如在适配器的缓存池有对应的适配器类,则回来对应的适配器类
  if (cachedAdaptiveClass != null) {
    return cachedAdaptiveClass;
  }
  // 假如在适配器缓存池中没有对应的适配类,则创立一个。
  return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
// 4.createAdaptiveExtensionClass() 创立一个适配器类
private Class<?> createAdaptiveExtensionClass() {
  // 生成适配器的源码
  String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
  // 类加载器
  ClassLoader classLoader = findClassLoader();
  // 经过SPI获取编译器的适配器类,再动态编译这个适配器的源码,生成类。
  org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
  return compiler.compile(code, classLoader);
}
// 5.new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
public String generate() {
  // 假如办法中没有@Adaptive注解,则抛反常
  if (!hasAdaptiveMethod()) {
    throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
  }
  StringBuilder code = new StringBuilder();
  // 生成package信息
  code.append(generatePackageInfo());
  // 生成import信息
  code.append(generateImports());
  // 生成类信息 public class %s$Adaptive implements....
  code.append(generateClassDeclaration());
  // 获取type的办法,生成办法信息 public %s %s(%s) %s {%s}
  Method[] methods = type.getMethods();
  for (Method method : methods) {
    code.append(generateMethod(method));
  }
  code.append("}");
  if (logger.isDebugEnabled()) {
    logger.debug(code.toString());
  }
  return code.toString();
}

3.常用办法loader.getActivateExtension(url, “”, “online”);课后评论:

// 1.生成主动激活的扩展类调集
public List<T> getActivateExtension(URL url, String key, String group) {
  // 获取URL的key对应的value
  String value = url.getParameter(key);
  // value即name,可以用","分隔
  return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
}
// 2,获取getActivateExtension()
public List<T> getActivateExtension(URL url, String[] values, String group) {
  List<T> exts = new ArrayList<>();
  List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);
  // 姓名中不包括"-default"
  if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
    // 1.加载默许的扩展器的称号
    // 2.加载各个目录下的SPI的服务供给者:
	  // 2.1.假如是适配器,则加载到适配器的缓存中(PS:在办法上加@Adaptive,不会被加载到适配器缓存池中)
    // 2.2.假如是装修器,则加载到装修器的缓存中
    // 2.3.加载主动激活的缓存中(cachedActivates)
    // 2.4 加载到缓存cachedNames中(k->class,v->name)
    getExtensionClasses();
    for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
      String name = entry.getKey();
      Object activate = entry.getValue();
      String[] activateGroup, activateValue;
      if (activate instanceof Activate) {
        activateGroup = ((Activate) activate).group();
        activateValue = ((Activate) activate).value();
      } else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
        // 适配alibaba版别的,现在的是apache版别
        activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
        activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
      } else {
        continue;
      }
      // activateGroup中包括了group
      if (isMatchGroup(group, activateGroup)) {
        // 获取扩展类的实例
        T ext = getExtension(name);
        if (!names.contains(name)
            && !names.contains(REMOVE_VALUE_PREFIX + name)
            && isActive(activateValue, url)) {
          // 符合上述要求则加到调集中
          exts.add(ext);
        }
      }
    }
    // 依据@Activate 排序
    exts.sort(ActivateComparator.COMPARATOR);
  }
  List<T> usrs = new ArrayList<>();
  for (int i = 0; i < names.size(); i++) {
    String name = names.get(i);
    // value的值不是以"-"开始,且 不包括"-"+$name
    if (!name.startsWith(REMOVE_VALUE_PREFIX)
        && !names.contains(REMOVE_VALUE_PREFIX + name)) {
      // 假如姓名为"default"
      if (DEFAULT_KEY.equals(name)) {
        if (!usrs.isEmpty()) {
          exts.addAll(0, usrs);
          usrs.clear();
        }
      } else {
        // 依据name获取Extension的实例,并放入usrs
        T ext = getExtension(name);
        usrs.add(ext);
      }
    }
  }
  if (!usrs.isEmpty()) {
    exts.addAll(usrs);
  }
  return exts;
}

总结

Dubbo 的SPI的优势:

  1. 有缓存(都有缓存)
  2. 可以结合Spring容器完成特点注入。
  3. 经过wrapper 装修器完成相似AOP的功用。
  4. 经过@Adaptive 装备适配器的类,就支持一个场景使用多种完成类。