Dubbo之SPI核心源码解析

Dubbo之SPI机制简介分享

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

我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块、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 CarCreateApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(CarCreateApplication.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);
流程

代码解析
// 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”);
流程

代码解析
// 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();
流程

代码解析
// 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 配置适配器的类,就支持一个场景使用多种实现类。

觉得博主写的还可以的,帮忙点个赞呗。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值