一、ExtensionLoader是什么?作用有哪些?

ExtensionLoader是服务发现、动态加载机制的具体实现。
ExtensionLoader的作用:
1、加载所有打上了@SPI注解的接口,生成动态适配器类,并根据配置动态选择具体的实现类。
2、实现简单ioc,对实现类的依赖属性进行setter注入(就是调用setXXX方法实现赋值)
3、对具体实现类进行包装wrapper,比如Protocol实现,每种具体的Protocol实现都经过 ProtocolListenerWrapper、
PtotocolFilterWrapper、QosProtocolWrapper的联合包装,用以实现服务监听、过滤。

二、重要属性

  1. //spi加载的路径
  2. private static final String SERVICES_DIRECTORY = "META-INF/services/";
  3. private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
  4. private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
  5. //??缓存每个打了SPI注解的接口类对应的ExtensionLoader实例
  6. private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
  7. //缓存每个实现类的实例,key:实现类Class,value:实现类实例
  8. private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
  9. //缓存接口实现类对应的别名,比如DubboProtocol类的别名是dubbo,key:实现类Class,value:别名
  10. private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();
  11. //缓存别名对应的实现类,key:别名,value:实现类Class。特别注意:这里的value是Class,不是实例对象
  12. private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>()
  13. //??
  14. private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
  15. //缓存实现类的实例对象信息,key:把别名,value:实现类实例对象的包装类
  16. private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
  17. //SPI接口实现类实例,这个实例可能是动态生成的接口适配器类,也可能是打了@Adaptive注解的类
  18. private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
  19. //每个SPI接口类的Adaptive实现类。想要参与SPI机制的接口类上都要打上@SPI注解,每个接口通常都有多种实现。
  20. //业务方如果指定实现,便用业务方指定的实现类;否则,使用默认的实现。通常默认的实现类别名在@SPI("dubbo")中
  21. //指定。那dubbo是如何支持动态选择实现类的呢?通常,会针对SPI接口生成一个适配器类,比如Protocol的适配器类
  22. //Protocol$Adaptive。在适配器中会根据业务参数进行选择具体实现类(实现类加载过后会被缓存到map中)
  23. //但如果某个实现类打上了@Adaptive注解,那么这个类就是默认实现,不会再为接口生成适配器类
  24. private volatile Class<?> cachedAdaptiveClass = null;
  25. //每个接口类的默认实现类的别名
  26. private String cachedDefaultName;
  27. //包装类,接口实现类的包装类,比如Protocol接口的包装类:ProtocolListenerWrapper、PtotocolFilterWrapper、QosProtocolWrapper
  28. private Set<Class<?>> cachedWrapperClasses;

三、重要方法

1、ExtensionLoader() : 构造方法

  1. private ExtensionLoader(Class<?> type) {
  2. this.type = type;
  3. objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
  4. }
  5. 1)这里可以看出每个SPI接口都有一个ExtensionFactory实现与之对应。每个封装了SPIExrtensionLoader都保存着
  6. 一个objectFactory对象,而objectFactory对象都是ExtensionFactory接口的@Adaptive实现,即
  7. AdaptiveExtensionFactory
  8. 2)那么这个ExtensionFactory的作用是什么呢?ExtensionLoader在进行ioc,给对象设置依赖的属性值时,
  9. objectFactory负责找到依赖的属性值,这个依赖值可能是Spring体系中的bean,也可能是其他的SPI扩展类。
  10. 其实ExtensionFactory接口有三个实现类,分别AdaptiveExtensionFactorySpiExtensionFactory
  11. SpringExtensionFactoryAdaptiveExtensionFactory是默认实现,但是没有具体的实现逻辑,它是依赖
  12. SpiExtensionFactorySpringExtensionFactory完成功能的。
  13. //factories是个列表,列表中只有两个元素,SpiExtensionFactory和SpringExtensionFactory
  14. public <T> T getExtension(Class<T> type, String name) {
  15. for (ExtensionFactory factory : factories) {
  16. T extension = factory.getExtension(type, name);
  17. if (extension != null) {
  18. return extension;
  19. }
  20. }
  21. return null;
  22. }

2、getAdaptiveExtension():获取动态适配器

  1. //每个SPI接口都有多种实现类,通常都会把对应的实现类实例后缓存起来(map),然后在构造一个接口的适配器类,
  2. //在适配器类中根据业务参数从缓存中动态选择具体的实现,用以完成业务功能
  3. public T getAdaptiveExtension() {
  4. //判断是否实例化过接口的Adaptive实现(要么是接口的适配器类,要么是接口的@Adaptive实现类)
  5. Object instance = cachedAdaptiveInstance.get();
  6. if (instance == null) {
  7. if (createAdaptiveInstanceError == null) {
  8. synchronized (cachedAdaptiveInstance) {
  9. instance = cachedAdaptiveInstance.get();
  10. if (instance == null) {
  11. try {
  12. //创建SPI接口的Adaptive实现
  13. instance = createAdaptiveExtension();
  14. cachedAdaptiveInstance.set(instance);
  15. } catch (Throwable t) {
  16. createAdaptiveInstanceError = t;
  17. throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
  18. }
  19. }
  20. }
  21. } else {
  22. throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
  23. }
  24. }
  25. return (T) instance;
  26. }

3、createAdaptiveExtension():创建SPI接口的Adaptive实现

  1. private T createAdaptiveExtension() {
  2. try {
  3. return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  4. } catch (Exception e) {
  5. throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
  6. }
  7. }
  8. NotesgetAdaptiveExtensionClass方法是真正实现的地方,injectExtension方法用以完成ioc功能

4、getAdaptiveExtensionClass():获取SPI接口的Adaptive实现的类信息

  1. private Class<?> getAdaptiveExtensionClass() {
  2. getExtensionClasses();
  3. if (cachedAdaptiveClass != null) {
  4. return cachedAdaptiveClass;
  5. }
  6. //如果SPI接口类没有@Adaptive实现类,则要创建适配器类
  7. return cachedAdaptiveClass = createAdaptiveExtensionClass();
  8. }

5、getExtensionClasses():加载SPI接口的各个实现类

  1. private Map<String, Class<?>> getExtensionClasses() {
  2. //判断是否加载过SPI接口的实现类
  3. Map<String, Class<?>> classes = cachedClasses.get();
  4. if (classes == null) {
  5. synchronized (cachedClasses) {
  6. classes = cachedClasses.get();
  7. if (classes == null) {
  8. //加载SPI接口的实现类
  9. classes = loadExtensionClasses();
  10. cachedClasses.set(classes);
  11. }
  12. }
  13. }
  14. return classes;
  15. }

6、loadExtensionClasses():加载SPI接口的实现类

  1. private Map<String, Class<?>> loadExtensionClasses() {
  2. cacheDefaultExtensionName();
  3. Map<String, Class<?>> extensionClasses = new HashMap<>();
  4. //主要看这个
  5. loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
  6. loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  7. loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
  8. loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  9. loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
  10. loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  11. return extensionClasses;
  12. }

7、loadDirectory():加载SPI接口的实现类

  1. private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
  2. String fileName = dir + type;
  3. try {
  4. Enumeration<java.net.URL> urls;
  5. //获取类加载器
  6. ClassLoader classLoader = findClassLoader();
  7. if (classLoader != null) {
  8. urls = classLoader.getResources(fileName);
  9. } else {
  10. urls = ClassLoader.getSystemResources(fileName);
  11. }
  12. if (urls != null) {
  13. while (urls.hasMoreElements()) {
  14. java.net.URL resourceURL = urls.nextElement();
  15. //真正加载的地方
  16. loadResource(extensionClasses, classLoader, resourceURL);
  17. }
  18. }
  19. } catch (Throwable t) {
  20. logger.error("Exception occurred when loading extension class (interface: " +
  21. type + ", description file: " + fileName + ").", t);
  22. }
  23. }

8、loadResource():加载SPI接口的实现类

  1. private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
  2. try {
  3. try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
  4. String line;
  5. while ((line = reader.readLine()) != null) {
  6. final int ci = line.indexOf('#');
  7. if (ci >= 0) {
  8. line = line.substring(0, ci);
  9. }
  10. line = line.trim();
  11. if (line.length() > 0) {
  12. try {
  13. String name = null;
  14. int i = line.indexOf('=');
  15. if (i > 0) {
  16. name = line.substring(0, i).trim();
  17. line = line.substring(i + 1).trim();
  18. }
  19. if (line.length() > 0) {
  20. //实例化加载的实现类
  21. loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
  22. }
  23. } catch (Throwable t) {
  24. IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
  25. exceptions.put(line, e);
  26. }
  27. }
  28. }
  29. }
  30. } catch (Throwable t) {
  31. logger.error("Exception occurred when loading extension class (interface: " +
  32. type + ", class file: " + resourceURL + ") in " + resourceURL, t);
  33. }
  34. }
  35. 这个功能要结合下面的截图看一下,如下图,实现类是以“别名=类全路径名”,根据类全路径名加载类

dubbo之ExtensionLoader(SPI)类源码分析 - 图1

9、loadClass():实例化加载的实现类

  1. //类的加载其实在loadResource方法中已经完成了,生成的clazz入参
  2. private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
  3. if (!type.isAssignableFrom(clazz)) {
  4. throw new IllegalStateException("Error occurred when loading extension class (interface: " +
  5. type + ", class line: " + clazz.getName() + "), class "
  6. + clazz.getName() + " is not subtype of interface.");
  7. }
  8. //判断该实现类是否有Adaptive注解,是的话就将该实现类赋值给cachedAdaptiveClass
  9. if (clazz.isAnnotationPresent(Adaptive.class)) {
  10. cacheAdaptiveClass(clazz);
  11. //判断该实现类是不是包装类,是的话将该实现类添加入cachedWrapperClasses集合中
  12. } else if (isWrapperClass(clazz)) {
  13. cacheWrapperClass(clazz);
  14. } else {
  15. clazz.getConstructor();
  16. if (StringUtils.isEmpty(name)) {
  17. name = findAnnotationName(clazz);
  18. if (name.length() == 0) {
  19. throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
  20. }
  21. }
  22. String[] names = NAME_SEPARATOR.split(name);
  23. if (ArrayUtils.isNotEmpty(names)) {
  24. //??
  25. cacheActivateClass(clazz, names[0]);
  26. for (String n : names) {
  27. //缓存实例类到cachedNames中
  28. cacheName(clazz, n);
  29. //缓存实例类到extensionClasses中,最终是赋值给cachedClasses
  30. saveInExtensionClass(extensionClasses, clazz, n);
  31. }
  32. }
  33. }
  34. }

10、createAdaptiveExtensionClass():创建适配器类

  1. private Class<?> createAdaptiveExtensionClass() {
  2. //适配器代码类的字符串表示
  3. String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
  4. ClassLoader classLoader = findClassLoader();
  5. //获取编译类
  6. org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
  7. //动态编译生成适配器类
  8. return compiler.compile(code, classLoader);
  9. }
  10. 这里以Protocol接口的适配器类举例,详见:
  11. https://note.youdao.com/web/#/file/WEB707524014b5f25df84f77a3a8fafedfa/note/WEB4da5d1bb4a6fac5bbd99d32155e11efa/

11、injectExtension():对实现类进行ioc操作

  1. //简单ioc,调用实现类的setXXX方法,为其注入依赖的类
  2. private T injectExtension(T instance) {
  3. try {
  4. if (objectFactory != null) {
  5. for (Method method : instance.getClass().getMethods()) {
  6. if (isSetter(method)) {
  7. if (method.getAnnotation(DisableInject.class) != null) {
  8. continue;
  9. }
  10. Class<?> pt = method.getParameterTypes()[0];
  11. if (ReflectUtils.isPrimitives(pt)) {
  12. continue;
  13. }
  14. try {
  15. String property = getSetterProperty(method);
  16. //这里就是AdaptiveExtensionFactory起作用的地方,找到依赖的类
  17. Object object = objectFactory.getExtension(pt, property);
  18. if (object != null) {
  19. method.invoke(instance, object);
  20. }
  21. } catch (Exception e) {
  22. logger.error("Failed to inject via method " + method.getName()
  23. + " of interface " + type.getName() + ": " + e.getMessage(), e);
  24. }
  25. }
  26. }
  27. }
  28. } catch (Exception e) {
  29. logger.error(e.getMessage(), e);
  30. }
  31. return instance;
  32. }

12、getExtension(String name):根据业务参数获取对应的实现类

  1. public T getExtension(String name) {
  2. if (StringUtils.isEmpty(name)) {
  3. throw new IllegalArgumentException("Extension name == null");
  4. }
  5. if ("true".equals(name)) {
  6. return getDefaultExtension();
  7. }
  8. //从cachedInstances中查找name对应的实现类
  9. final Holder<Object> holder = getOrCreateHolder(name);
  10. Object instance = holder.get();
  11. if (instance == null) {
  12. synchronized (holder) {
  13. instance = holder.get();
  14. if (instance == null) {
  15. //若name对应的实现类不存在,则创建实现类
  16. instance = createExtension(name);
  17. holder.set(instance);
  18. }
  19. }
  20. }
  21. return (T) instance;
  22. }
  23. //缓存SPI实现类的包装类Holder。从cachedInstances中查找,有则返回,无则创建
  24. private Holder<Object> getOrCreateHolder(String name) {
  25. Holder<Object> holder = cachedInstances.get(name);
  26. if (holder == null) {
  27. cachedInstances.putIfAbsent(name, new Holder<>());
  28. holder = cachedInstances.get(name);
  29. }
  30. return holder;
  31. }

13、createExtension(String name):根据业务参数创建SPI实现类

  1. private T createExtension(String name) {
  2. //
  3. Class<?> clazz = getExtensionClasses().get(name);
  4. if (clazz == null) {
  5. throw findException(name);
  6. }
  7. try {
  8. T instance = (T) EXTENSION_INSTANCES.get(clazz);
  9. if (instance == null) {
  10. //缓存中若没有name对应的实现类实例,则通过反射生成
  11. EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
  12. instance = (T) EXTENSION_INSTANCES.get(clazz);
  13. }
  14. injectExtension(instance);
  15. //这个是精华了,如果SPI接口有相应的包装类,则在此处会对原始invoker进行层层包装,链式调用
  16. //以Protocol为例,它的包装类有三个,分别是:
  17. Set<Class<?>> wrapperClasses = cachedWrapperClasses;
  18. if (CollectionUtils.isNotEmpty(wrapperClasses)) {
  19. for (Class<?> wrapperClass : wrapperClasses) {
  20. instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
  21. }
  22. }
  23. return instance;
  24. } catch (Throwable t) {
  25. throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
  26. type + ") couldn't be instantiated: " + t.getMessage(), t);
  27. }
  28. }
  29. //判断cachedClasses中是否有有效元素,若有则直接返回,若没有则调用loadExtensionClasses方法,
  30. //加载一遍SPI接口对应的实现类。以Protocol接口为例,这个cachedClasses中呢应该有DubboProtocol、
  31. //RestProtocol、RegistryProtocol等类的class信息
  32. private Map<String, Class<?>> getExtensionClasses() {
  33. Map<String, Class<?>> classes = cachedClasses.get();
  34. if (classes == null) {
  35. synchronized (cachedClasses) {
  36. classes = cachedClasses.get();
  37. if (classes == null) {
  38. classes = loadExtensionClasses();
  39. cachedClasses.set(classes);
  40. }
  41. }
  42. }
  43. return classes;
  44. }

四、dubbo的spi路径

dubbo之ExtensionLoader(SPI)类源码分析 - 图2