Dubbo之SPI机制简介分享

SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。

我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块、xml解析模块、jdbc模块等方案。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。 Java SPI就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

Java的SPI机制: ServiceLoader

用法

// java.sql.Driver// 1.new一个ServiceLoaderServiceLoader drivers = ServiceLoader.load(Driver.class);Iterator iterator = drivers.iterator();// 2.调用延迟加载器的hashNextwhile (iterator.hasNext()) {  // 3.调用延迟加载器的  nextDriver next = iterator.next();  System.out.println(next.getClass());}// result:class com.mysql.jdbc.Driverclass com.mysql.fabric.jdbc.FabricMySQLDriverclass com.alibaba.druid.proxy.DruidDriverclass com.alibaba.druid.mock.MockDriver

原理

ServiceLoader并不会在load的时候去加载所有 接口对应实现类的文件。而是在执行接口的时候去遍历加载。

ServiceLoader的核心属性

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

LazyIterator的核心属性

// 接口类型Class service;// 接的加载器ClassLoader loader;// META-INF/services/内配置文件的URL集合Enumeration configs = null;// 需加载的实现类的全包名集合Iterator pending = null;// 下一个实现类的全报名,用于迭代器延迟加载的下一个类String nextName = null;

源码解析

1、load方法

// 1、load方法public static  ServiceLoader load(Class service) {    // 获取当前线程的类加载器    ClassLoader cl = Thread.currentThread().getContextClassLoader();    // 继续调用重载的方法    return ServiceLoader.load(service, cl);}// 2、调用重载方法public static  ServiceLoader load(Class service, ClassLoader loader) {    // new 一个ServiceLoader对象    return new ServiceLoader<>(service, loader);}// 3、new 一个serviceLoader对象private ServiceLoader(Class 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 LazyIteratorprivate LazyIterator(Class 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 action = new PrivilegedAction() {    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 action = new PrivilegedAction() {      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 Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

3.用SpringBoot启动

@SpringBootApplicationpublic 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 configurations = this.getCandidateConfigurations(annotationMetadata, attributes);    configurations = this.removeDuplicates(configurations);    Set 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 getCandidateConfigurations(AnnotationMetadata metadata,                                                   AnnotationAttributes attributes) {  // 获取configurations  List 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 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> cache = new ConcurrentReferenceHashMap<>();
// 6.执行loadSpringFactories()方法,根据类加载器,获取META-INF/spring.factories下的配置private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {  // 在缓存池中获取,有则直接返回。  MultiValueMap result = cache.get(classLoader);  if (result != null) {    return result;  }  try {    // 获取"META-INF/spring.factories"的URL    Enumeration 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 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.接口实现AlipayOrderpublic class AlipayOrder implements Order {  @Override  public String way() {    System.out.println("--- 支付宝way() ---");    return "支付宝支付方式";  }}// 3.接口实现WeChatOrderpublic 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 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 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 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, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();// 存储的是 每个SPI接口的多个实现类和对应实例之间的关系private static final ConcurrentMap, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();// 接口的类型private final Class<?> type;// 获取工厂类,用于获取Spring容器中的Beanprivate final ExtensionFactory objectFactory;// 扩展类和扩展名称映射关系private final ConcurrentMap, String> cachedNames = new ConcurrentHashMap<>();// 扩展名称和扩展类类型映射关系private final Holder>> cachedClasses = new Holder<>();// 扩展名称和自动激活扩展类映射关系private final Map cachedActivates = new ConcurrentHashMap<>();// 扩展名称和扩展类实例映射关系private final ConcurrentMap> cachedInstances = new ConcurrentHashMap<>();// 自适应扩展类实例缓存private final Holder cachedAdaptiveInstance = new Holder<>();// 自适应扩展类private volatile Class<?> cachedAdaptiveClass = null;// 默认的服务提供者的名称private String cachedDefaultName;// 包装扩展类集合private Set> cachedWrapperClasses;

源码解析

ExtensionLoader.getExtensionLoader(Order.class);

流程

代码解析

// 1.ExtensionLoader.getExtensionLoader源码public static  ExtensionLoader getExtensionLoader(Class 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 loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);  if (loader == null) {    // 不存在,则new一个对应SPI的ExtensionLoader(***重点***)    EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));    // 添加到缓存池中    loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);  }  return loader;}// withExtensionAnnotation方法private static  boolean withExtensionAnnotation(Class type) {  return type.isAnnotationPresent(SPI.class);}// 2.new ExtensionLoader(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> loadExtensionClasses() {  // 1.获取SPI的value获取默认名字 加载默认的扩展器的名称  cacheDefaultExtensionName();  // 2. 加载各个目录下的SPI的配置文件  // 2.1.如果是适配器,则加载到适配器的缓存中  // 2.2.如果是装饰器,则加载到装饰器的缓存中  // 2.3.把name加载自动激活的缓存中,把name到SPI的name缓存池,把SPI name和类的对应关系缓存到  Map> 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> extensionClasses, String dir, String type) {  String fileName = dir + type;  try {    Enumeration 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> 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");

流程

代码解析

// 1.获取Order的名称为"alipay"的SPIpublic 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 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> 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 getExtension(Class 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();

流程

代码解析

// 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 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 getActivateExtension(URL url, String[] values, String group) {  List exts = new ArrayList<>();  List 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 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 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 配置适配器的类,就支持一个场景使用多种实现类。
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章