SPI全称是Service Provider Interface,是一种服务自发现机制,本质是将接口实现类的全限定名配置在文件中,在使用中,通过运行时加载,并动态地替换为具体的接口实现类。
以下内容基于Dubbo 2.7.12版本
JDK SPI 在开发中,SPI的应用中最让我们熟知的便是JDBC的使用,JDBC中定义了java.sql.Driver 接口,当我们调用DriverManager#getConnection方法时 ,将触发DriverManager 类的初始化,并利用SPI机制自动加载驱动类:
1 2 3 4 static { loadInitialDrivers(); println("JDBC DriverManager initialized" ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private static void loadInitialDrivers () { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run () { ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class); Iterator<Driver> driversIterator = loadedDrivers.iterator(); try { while (driversIterator.hasNext()) { driversIterator.next(); } } catch (Throwable t) { } return null ; } }); }
在调用ServiceLoader#load 时,将首先获取当前线程绑定的类加载器(ServiceLoader由启动类加载器加载,启动类加载器无法加载应用类代码):
1 2 3 4 public static <S> ServiceLoader<S> load (Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); }
随后将对迭代器driversIterator 进行遍历,加载META-INF/services/java.sql.Driver 路径下所有的文件,并按行读取 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private boolean hasNextService () { if (nextName != null ) { return true ; } if (configs == null ) { try { 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); } } while ((pending == null ) || !pending.hasNext()) { if (!configs.hasMoreElements()) { return false ; } pending = parse(service, configs.nextElement()); } nextName = pending.next(); return true ; }
回到**driversIterator.next()**的调用中,会触发具体驱动类的加载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 private S nextService() { if (!hasNextService()) throw new NoSuchElementException(); 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(); // This cannot happen }
以MySQL为例,加载的类为com.mysql.cj.jdbc ,可以看到该段初始化代码中会通过DriverManager#registerDriver 注册当前驱动类:
1 2 3 4 5 6 7 8 9 public class Driver extends NonRegisteringDriver implements java .sql .Driver { static { try { DriverManager.registerDriver(new Driver()); } catch (SQLException var1) { throw new RuntimeException("Can't register driver!" ); } } }
在整个流程中,我们可以看出,JDK的SPI会一次性的加载并实例化,通过配置文件发现的所有的服务实现类,如果存在多个服务实现类,而我们只需要其中一个的话,则在一定程度上损耗了资源。
Dubbo SPI实现 在Dubbo中,所有的组件组件都是由SPI进行加载,但Dubbo并示直接使用JDK提供的SPI机制,而是借鉴其核心思想,并对其进行了增强,实现了自身的一套SPI机制,其用法与JDK的类似,核心类是ExtensionLoader ,配置文件也定义在**META-INF/**路径下,但Dubbo对配置文件具体分为了三类:
META-INF/services/ 目录:该目录下的 SPI 配置文件用来兼容 JDK SPI 。
META-INF/dubbo/ 目录:该目录用于存放用户自定义 SPI 配置文件。
META-INF/dubbo/internal/ 目录:该目录用于存放 Dubbo 内部使用的 SPI 配置文件。
且配置文件的内容也不再是类名,而是K-V形式,key被称为扩展名,value则是扩展实现类,并通指定扩展名实现按需加载:
1 dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
示例 定义扩展接口:
1 2 3 4 @SPI public interface Animal { String name () ; }
定义扩展实现:
1 2 3 4 5 6 public class Cat implements Animal { @Override public String name () { return "I'm a cat" ; } }
1 2 3 4 5 6 public class Dog implements Animal { @Override public String name () { return "I'm a dog" ; } }
配置文件,位置:META-INF/dubbo/org.apache.dubbo.mytest.Animal:
1 2 cat=org.apache.dubbo.mytest.Cat dog=org.apache.dubbo.mytest.Dog
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 public class MyExtensionLoaderTest { @Test public void test () { ExtensionLoader<Animal> extensionLoader = ExtensionLoader.getExtensionLoader(Animal.class); Animal cat = extensionLoader.getExtension("cat" ); System.out.println(cat.name()); Animal dog = extensionLoader.getExtension("dog" ); System.out.println(dog.name()); } }
源码分析 获取ExtensionLoader实例 1 2 3 4 5 6 7 8 9 public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { //省略... ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); if (loader == null) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader; }
可以看出,通过EXTENSION_LOADERS缓存字段,保证一个扩展接口有且只有一个ExtensionLoader实例。
获取扩展实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public T getExtension (String name, boolean wrap) { if (StringUtils.isEmpty(name)) { throw new IllegalArgumentException("Extension name == null" ); } if ("true" .equals(name)) { return getDefaultExtension(); } final Holder<Object> holder = getOrCreateHolder(name); Object instance = holder.get(); if (instance == null ) { synchronized (holder) { instance = holder.get(); if (instance == null ) { instance = createExtension(name, wrap); holder.set(instance); } } } return (T) instance; }
先检查缓存 ,没有则通过createExtension 创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 private T createExtension (String name, boolean wrap) { Class<?> clazz = getExtensionClasses().get(name); if (clazz == null || unacceptableExceptions.contains(name)) { throw findException(name); } try { T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null ) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } injectExtension(instance); if (wrap) { List<Class<?>> wrapperClassesList = new ArrayList<>(); if (cachedWrapperClasses != null ) { wrapperClassesList.addAll(cachedWrapperClasses); wrapperClassesList.sort(WrapperComparator.COMPARATOR); Collections.reverse(wrapperClassesList); } if (CollectionUtils.isNotEmpty(wrapperClassesList)) { for (Class<?> wrapperClass : wrapperClassesList) { Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); if (wrapper == null || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } } } initExtension(instance); return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: " + t.getMessage(), t); } }
可以看到,createExtension 主要包含了4个步骤:
通过getExtensionClasses获取所有扩展实现类;
获取/通过反射创建扩展实例;
向扩展实例注入依赖;
包装扩展实例;
获取所有的扩展类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private Map<String, Class<?>> getExtensionClasses() { Map<String, Class<?>> classes = cachedClasses.get(); if (classes == null ) { synchronized (cachedClasses) { classes = cachedClasses.get(); if (classes == null ) { classes = loadExtensionClasses(); cachedClasses.set(classes); } } } return classes; }
通过loadExtensionClasses 加载扩展类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private Map<String, Class<?>> loadExtensionClasses() { cacheDefaultExtensionName(); Map<String, Class<?>> extensionClasses = new HashMap<>(); for (LoadingStrategy strategy : strategies) { loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache" , "com.alibaba" ), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); } return extensionClasses; }
这里首先解析了@SPI注解,获取到默认的扩展名并缓存下来,然后通过不同的策略加载扩展类,那这里的策略都有哪些呢,通过定位可以看到是通过loadLoadingStrategies 获取的:
1 2 3 4 5 private static LoadingStrategy[] loadLoadingStrategies() { return stream(load(LoadingStrategy.class).spliterator(), false ) .sorted() .toArray(LoadingStrategy[]::new ); }
继续深入可以发现,该策略是最终是通过JDK的SPI机制加载的,而通过配置文件可以看到主要包含了有一种策略类org.apache.dubbo.common.extension.DubboInternalLoadingStrategy 、org.apache.dubbo.common.extension.DubboLoadingStrategy 、org.apache.dubbo.common.extension.ServicesLoadingStrategy ,而这3种策略类则分别对应了前端提到的3个配置文件的目录。
回到loadDirectory 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 private void loadDirectory (Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) { String fileName = dir + type; try { Enumeration<java.net.URL> urls = null ; ClassLoader classLoader = findClassLoader(); if (extensionLoaderClassLoaderFirst) { ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader(); if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) { urls = extensionLoaderClassLoader.getResources(fileName); } } if (urls == null || !urls.hasMoreElements()) { 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, overridden, excludedPackages); } } } catch (Throwable t) { logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ")." , t); } }
获取到了对应所有的文件资源,并通过loadResource 加载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 private void loadResource (Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL, boolean overridden, String... excludedPackages) { try { try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) { String line; String clazz = null ; while ((line = reader.readLine()) != null ) { final int ci = line.indexOf('#' ); if (ci >= 0 ) { line = line.substring(0 , ci); } line = line.trim(); if (line.length() > 0 ) { try { String name = null ; int i = line.indexOf('=' ); if (i > 0 ) { name = line.substring(0 , i).trim(); clazz = line.substring(i + 1 ).trim(); } else { clazz = line; } if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) { loadClass(extensionClasses, resourceURL, Class.forName(clazz, true , classLoader), name, overridden); } } catch (Throwable t) { IllegalStateException e = new IllegalStateException( "Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t); exceptions.put(line, e); } } } } } catch (Throwable t) { logger.error("Exception occurred when loading extension class (interface: " + type + ", class file: " + resourceURL + ") in " + resourceURL, t); } }
加载扩展类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private void loadClass (Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name, boolean overridden) 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, overridden); } 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)) { cacheActivateClass(clazz, names[0 ]); for (String n : names) { cacheName(clazz, n); saveInExtensionClass(extensionClasses, clazz, n, overridden); } } } }
从代码分支上看,加载扩展类这里分为3种情况,分别为自适应扩展类、包装类及普通扩展类:
该类上有Adaptive ,为自适应扩展类;
该类有扩展类类型的构造函数,则为包装类;
其他为普通扩展类;
依赖注入 创建扩展实例后,下一步则是向扩展实例注入依赖,具体逻辑是injectExtension :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 private T injectExtension (T instance) { if (objectFactory == null ) { return instance; } try { for (Method method : instance.getClass().getMethods()) { if (!isSetter(method)) { continue ; } if (method.getAnnotation(DisableInject.class) != null ) { continue ; } Class<?> pt = method.getParameterTypes()[0 ]; if (ReflectUtils.isPrimitives(pt)) { continue ; } String property = getSetterProperty(method); Inject inject = method.getAnnotation(Inject.class); if (inject == null ) { injectValue(instance, method, pt, property); } else { if (!inject.enable()) { continue ; } if (inject.type() == Inject.InjectType.ByType) { injectValue(instance, method, pt, null ); } else { injectValue(instance, method, pt, property); } } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance; }
1 2 3 4 5 6 7 8 9 10 11 private void injectValue (T instance, Method method, Class<?> pt, String property) { try { 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); } }
可以看到,这里的依赖注入是通过解析set方法进行注入,可以通过类型或名称进行注入,具体的注入逻辑由objectFactory 决定,通过深入查看发现此处objectFactory 通过ExtensionLoader#getAdaptiveExtension 方法获取得到,其类型为AdaptiveExtensionFactory ,该类被称为自适应扩展类,而它也是通过SPI机制加载得到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() { ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List<ExtensionFactory> list = new ArrayList<ExtensionFactory>(); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } factories = Collections.unmodifiableList(list); } @Override public <T> T getExtension(Class<T> type, String name) { //遍历所有ExtensionFactory,获取到依赖后便直接返回 for (ExtensionFactory factory : factories) { T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; } }
而AdaptiveExtensionFactory 中维护了factories集合,在Spring环境下,该集合包括SpiExtensionFactory 和SpringExtensionFactory 。
获取自适应扩展类 什么是自适应扩展类呢?在前文了解到,Dubbo的依赖注入有用到自适应扩展类,通过观察其实现,可以发现它实际上是一种代理类。在Dubbo中,可以通过**@Adaptive注解标注扩展接口或接口方法,而Dubbo将自动为其生成具有代理功能的代码,并通过编译得到Class类,当调用自适应扩展类时,将通过方法中的URL参数决定具体调用的扩展实例。其关键代码在于 getAdaptiveExtension**:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public T getAdaptiveExtension () { Object instance = cachedAdaptiveInstance.get(); if (instance == null ) { if (createAdaptiveInstanceError != null ) { throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null ) { try { instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { createAdaptiveInstanceError = t; throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); } } } } return (T) instance; }
1 2 3 4 5 6 7 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 :
1 2 3 4 5 6 7 private Class<?> getAdaptiveExtensionClass() { getExtensionClasses(); if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } return cachedAdaptiveClass = createAdaptiveExtensionClass(); }
getAdaptiveExtensionClass 同样包含了3个步骤:
获取扩展类(与获取普通的扩展类的调用是同一个方法,这里会缓存**@Adaptive**注解标注的类为cachedAdaptiveClass);
缓存的自适应扩展类cachedAdaptiveClass不为空时,直接返回;
创建自适应扩展类;
1 2 3 4 5 6 7 8 9 10 private Class<?> createAdaptiveExtensionClass() { String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate(); ClassLoader classLoader = findClassLoader(); org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
createAdaptiveExtensionClass用于生成自适应扩展类代码,并通过org.apache.dubbo.common.compiler.Compiler 实例编码代码,得到Class类。通过查看其配置文件可知,目前存在JdkCompiler 和JavassistCompiler 两种编译器,而Dubbo默认使用JavassistCompiler 。
那生成的自适应扩展类是什么样的呢,这里以ProxyFactory 为例,使用arthas工具反编译得到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class ProxyFactory $Adaptive implements ProxyFactory { public Object getProxy (Invoker invoker) throws RpcException { if (invoker == null ) { throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null" ); } if (invoker.getUrl() == null ) { throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null" ); } URL uRL = invoker.getUrl(); String string = uRL.getParameter("proxy" , "javassist" ); if (string == null ) { throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" ).append(uRL.toString()).append(") use keys([proxy])" ).toString()); } ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(string); return proxyFactory.getProxy(invoker); } public Object getProxy (Invoker invoker, boolean bl) throws RpcException { if (invoker == null ) { throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null" ); } if (invoker.getUrl() == null ) { throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null" ); } URL uRL = invoker.getUrl(); String string = uRL.getParameter("proxy" , "javassist" ); if (string == null ) { throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" ).append(uRL.toString()).append(") use keys([proxy])" ).toString()); } ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(string); return proxyFactory.getProxy(invoker, bl); } public Invoker getInvoker (Object object, Class clazz, URL uRL) throws RpcException { if (uRL == null ) { throw new IllegalArgumentException("url == null" ); } URL uRL2 = uRL; String string = uRL2.getParameter("proxy" , "javassist" ); if (string == null ) { throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" ).append(uRL2.toString()).append(") use keys([proxy])" ).toString()); } ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(string); return proxyFactory.getInvoker(object, clazz, uRL); } }
可以看到,自适应扩展类就是通过获取指定URL参数,来动态决定扩展实现类。
自动包装类 回到ExtensionLoader#loadClass 方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name, boolean overridden) throws NoSuchMethodException { //省略... if (clazz.isAnnotationPresent(Adaptive.class)) { cacheAdaptiveClass(clazz, overridden); //是否包含拷贝构造函数 } else if (isWrapperClass(clazz)) { //缓存包装类 cacheWrapperClass(clazz); } else { //省略... } }
那包装类是什么呢,通过查看cachedWrapperClasses的使用位置,可以看到,在ExtensionLoader#createExtension 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 if (wrap) { List<Class<?>> wrapperClassesList = new ArrayList<>(); if (cachedWrapperClasses != null) { wrapperClassesList.addAll(cachedWrapperClasses); wrapperClassesList.sort(WrapperComparator.COMPARATOR); Collections.reverse(wrapperClassesList); } if (CollectionUtils.isNotEmpty(wrapperClassesList)) { for (Class<?> wrapperClass : wrapperClassesList) { Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); if (wrapper == null || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } } }
包装类是一种装饰类,其作用更多用于将扩展类的公共逻辑处理。
总结 本文简单介绍了 Java SPI 与 Dubbo SPI 用法,并通过源码分析了 Dubbo SPI 加载拓展类的过程,总的来说,
Dubbo实现了自己的一套SPI机制,可以按需进行加载;
在Dubbo中可以通过**@Adaptive**注解创建自适应扩展类,根据传入的URL参数加载具体的扩展实现;
Dubbo可以对创建的扩展实例进行依赖注入,但只针对setter方法进行注入,目前存在两种注入实现,分别为SpiExtensionFactory 和SpringExtensionFactory ;
Dubbo可以通过包装类实现对扩展类的装饰;