springboot的Spi机制 结合之前说到的springboot的Spi机制 本篇将简单介绍一下Doubbo
的SPI机制,Dobbo
没有使用jdk
的这套SPI
机制,而是自己实现了一套,提供了一些更灵活、更易于使用的方式。
简单回顾下,SPI全称(Service Provider Interface)是一种服务发现机制,本质上是将接口的实现类的全限定类名写在配置文件中,并由类加载器读取配置文件,这样可以在运行时,动态为接口替换实现类,所以一般用这种方式来为服务提供扩展能力。
JDK的服务发现spi机制 JDK 的 SPI 规范规定:
接口名
:可随意定义
实现类名
:可随意定义
提供者配置文件路径
: 其查找的目录为 META-INF/services
提供者配置文件名称
:接口的全限定性类名,没有扩展名。
提供者配置文件内容
:该接口的所有实现类的全限类性类名写入到该文件中,一个类名占一行
案例 定义一个接口:
1 2 3 public interface CarService { void run () ; }
接口实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class ElectricCarServiceImpl implements CarService { @Override public void run () { System.out.println("ElectricCarServiceImpl run" ); } } public class TankCarServiceImpl implements CarService { @Override public void run () { System.out.println("TankCarServiceImpl run" ); } }
创建配置文件(META-INF/services/cn.com.xiaocainiaoya.spi.jdk.CarService),然后在配置文件中配置接口的实现类的全限定类名:
1 2 cn.com.xiaocainiaoya.spi.jdk.ElectricCarServiceImpl cn.com.xiaocainiaoya.spi.jdk.TankCarServiceImpl
模拟客户端:
1 2 3 4 5 6 7 8 9 10 11 public class CarMain { public static void main (String[] args) { ServiceLoader<CarService> loader = ServiceLoader.load(CarService.class); Iterator<CarService> it = loader.iterator(); while (it.hasNext()) { CarService service = it.next(); service.run(); } } }
最终输出:
1 2 ElectricCarServiceImpl run TankCarServiceImpl run
这种方式有几个问题:
获取实现类的方式不够灵活,只能通过loader.iterator()
迭代器的方式来获取实现类,然后遍历判定当前要使用的实现类,假设说可以以键值对的方式来获取实现类,那么可以增加一定的便利。
不能按需加载,比如某个接口在配置文件中配置的实现类有很多,但是实际在运行过程中只需要其中的小几个,虽然ServiceLoader做了延迟载入,但是获取实现类的手段只能通过遍历来获取,基本上实现类都得加载并实例化。
ServiceLoader类的实例是线程不安全。
Dubbo的服务发现机制SPI Dobbo没有使用Java
的这套SPI机制,而是自己实现了一套功能更加强大的SPI机制,Dubbo的SPI是通过ExtensionLoader
类来进行实现类加载。
先来简单理解一下Dubbo这套SPI机制中的一些概念:
接口名: 可以随意定义,但接口必须被@SPI 注解修饰
实现类名: 在接口名前添加一个用于表示自身功能的“标识前辍”字符串
提供者配置文件路径: 在依次查找的目录为
META-INF/dubbo/internal
META-INF/dubbo
META-INF/services
提供者配置文件名称: 接口的全限定性类名,无需扩展名
提供者配置文件内容: 文件的内容为 key=value 形式
, value 为该接口的实现类的全限类性类名, key 可以随意,但一般为该实现类的“标识前辍”(首字母小写)。一个类名占一行。
提供者加载: ExtensionLoader 类相当于 JDK SPI 中的 ServiceLoader 类,用于加载提供者配置文件中所有的实现类,并创建相应的实例。
增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接使用 setter() 方法注入其他扩展点 ,也可 以对扩展点使用 Wrapper 类进行功能增强。
一些名词解释:
普通扩展类:就是接口的具体的实现类(对应JDK的SPI中的具体的实现类)
Adaptive类:自适应扩展类,就是类似于在普通扩展类上再包一层,客户端获取到这个自适应扩展类,通过这个扩展类调用定义的扩展接口,它会根据一定的规则(自适应扩展类的接口的参数需要有com.alibaba.dubbo.common.URL)来路由到对应的实现类中。
Wrapper类:包装类,对普通扩展类的包装机制,可以对扩展类的SPI接口方法进行增强,一个SPI可以包含多个Wrapper。
Activate类:激活类,激活扩展类,可以通过指定的条件来一下子把需要的扩展类激活(因为Dubbo这套机制是按需加载,也就使用到时再进行加载,但是有些场景,可能一下子就要把某一些规则「比如做了分组,要把某个组的类一下子都加载」的类进行加载)
普通扩展类 定义接口:
1 2 3 4 @SPI("car") public interface CarService { void run () ; }
实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ElectricCarServiceImpl implements CarService { @Override public void run () { System.out.println("ElectricCarServiceImpl run" ); } } public class TankCarServiceImpl implements CarService { @Override public void run () { System.out.println("TankCarServiceImpl run" ); } }
创建META-INF/services/cn.com.xiaocainiaoya.spi.dubbo.CarService
文件,并添加配置:
注: 这里与JDK
的SPI稍有不同,这是是自定为每个接口实现定义了一个key。
1 2 electric =cn.com.xiaocainiaoya.spi.dubbo.ElectricCarServiceImpl tank =cn.com.xiaocainiaoya.spi.dubbo.TankCarServiceImpl
客户端:
1 2 3 4 5 6 7 8 9 public class CarMain { public static void main (String[] args) { ExtensionLoader<CarService> loader = ExtensionLoader.getExtensionLoader(CarService.class); CarService car = loader.getExtension("electric" ); car.run(); } }
自适应扩展类Adaptive 自适应扩展@Adaptive
注解可以标记在类上,也可以标记在方法上。
1.标记在类上 定义接口:
1 2 3 4 5 6 7 @SPI("electric") public interface CarService { void display () ; void run () ; }
实现类:
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 public class ElectricCarServiceImpl implements CarService { @Override public void display () { System.out.println("ElectricCarServiceImpl display" ); } @Override public void run () { System.out.println("ElectricCarServiceImpl run" ); } } public class TankCarServiceImpl implements CarService { @Override public void display () { System.out.println("TankCarServiceImpl display" ); } @Override public void run () { System.out.println("TankCarServiceImpl run" ); } } @Adaptive public class AdaptiveCarServiceImpl implements CarService { private String defaultName; public void setDefaultName (String defaultName) { this .defaultName = defaultName; } @Override public void display () { ExtensionLoader<CarService> loader = ExtensionLoader.getExtensionLoader(CarService.class); CarService carService; if (StringUtils.isEmpty(defaultName)) { carService = loader.getDefaultExtension(); } else { carService = loader.getExtension(defaultName); } carService.display(); } }
配置文件:
注意一个@SPI
接口只能有一个标记@Adaptive
在类上的实现,所以在有这个要求的情况下,这个类的在下面配置文件中的key
就显得无关紧要,这里是叫adaptive
,你可以叫其他名字。
那么假设某个接口有两个标记了@Adaptive
类,并且两个类都写在了下方的配置文件中会怎么样?
在ExtensionLoader#loadFile()
方法中逐行扫描这些配置文件时,会发现某个@SPI
接口有两个@Adaptive
的实现类,后一个扫描到时会中断,之后它的做法是把异常信息保存在Map<String, IllegalStateException> exceptions
,并不会使得程序都中断。也就是说假设有两个@Apdative
的情况下,最终加载的是靠前的那个实现。
1 2 3 electric =cn.com.xiaocainiaoya.spi.dubbo.adaptive.ElectricCarServiceImpltank =cn.com.xiaocainiaoya.spi.dubbo.adaptive.TankCarServiceImpladaptive =cn.com.xiaocainiaoya.spi.dubbo.adaptive.AdaptiveCarServiceImpl
客户端:
1 2 3 4 5 6 7 8 9 10 11 public class CarMain { public static void main (String[] args) { ExtensionLoader<CarService> loader = ExtensionLoader.getExtensionLoader(CarService.class); CarService carService = loader.getAdaptiveExtension(); ((AdaptiveCarServiceImpl)carService).setDefaultName("tank" ); carService.display(); Set<String> supportedExtensions = loader.getSupportedExtensions(); System.out.println(supportedExtensions); } }
输出:
1 2 TankCarServiceImpl display [electric, tank]
2.标记在方法上 定义接口:
1 2 3 4 5 6 7 8 9 @SPI("electric") public interface CarService { void display () ; @Adaptive void run (URL url) ; }
实现类:
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 public class ElectricCarServiceImpl implements CarService { @Override public void display () { System.out.println("ElectricCarServiceImpl display" ); } @Override public void run (URL url) { System.out.println("ElectricCarServiceImpl run" ); } } public class TankCarServiceImpl implements CarService { @Override public void display () { System.out.println("TankCarServiceImpl display" ); } @Override public void run (URL url) { System.out.println("TankCarServiceImpl run" ); } }
将@Adaptive
标记在方法上时,会通过javassist
为该接口生成一个动态类CarService$Adaptive
,这个自动生成的代理类的主要作用是根据URL
这个类来传入路由规则,使得此类可以根据这个路由规则,找到具体的实现类。(这个类是动态生成的,这就导致了不能通过IDE打断点之类的方式进行调试)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package cn.com.xiaocainiaoya.spi.dubbo.adaptive;import com.alibaba.dubbo.common.extension.ExtensionLoader;public class CarService $Adaptive implements cn .com .xiaocainiaoya .spi .dubbo .adaptive .CarService { public void display () { throw new UnsupportedOperationException("method public abstract void cn.com.xiaocainiaoya.spi.dubbo.adaptive" + ".CarService.display() of interface cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService is not " + "adaptive method!" ); } public void run (com.alibaba.dubbo.common.URL arg0) { if (arg0 == null ) throw new IllegalArgumentException("url == null" ); com.alibaba.dubbo.common.URL url = arg0; String extName = url.getParameter("car.service" , "electric" ); if (extName == null ) throw new IllegalStateException("Fail to get extension(cn.com.xiaocainiaoya.spi.dubbo.adaptive" + ".CarService) name from url(" + url.toString() + ") use keys([car.service])" ); cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService extension = (cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService) ExtensionLoader.getExtensionLoader(cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService.class).getExtension(extName); extension.run(arg0); } }
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CarMain { public static void main (String[] args) { ExtensionLoader<CarService> loader = ExtensionLoader.getExtensionLoader(CarService.class); CarService car = loader.getAdaptiveExtension(); URL url = URL.valueOf("xxx" ); car.run(url); URL url2 = URL.valueOf("xxx?car.service=tank" ); car.run(url2); car.display(); } }
执行结果:
1 2 ElectricCarServiceImpl run TankCarServiceImpl run
3.小结 对比两种对于@Adaptive
标记的位置的不同,可以发现,其实标记在类上,就是需要自己去实现路由规则,由自己来控制怎么找到自己需要的实现类;标记在接口上,是Dubbo
通过做了一层高度抽象,配合URL
类和根据javassist
动态生成自适应扩展类,来路由到具体需要使用到的实现类。
包装机制Wrapper 定义接口:
1 2 3 4 5 6 7 8 @SPI("electric") public interface CarService { void display () ; @Adaptive void run (URL url) ; }
实现类:
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 public class ElectricCarServiceImpl implements CarService { @Override public void display () { System.out.println("ElectricCarServiceImpl display" ); } @Override public void run (URL url) { System.out.println("ElectricCarServiceImpl run" ); } } public class TankCarServiceImpl implements CarService { @Override public void display () { System.out.println("TankCarServiceImpl display" ); } @Override public void run (URL url) { System.out.println("TankCarServiceImpl run" ); } }
包装类:
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 public class CarServiceWrapper implements CarService { private CarService carService; public CarServiceWrapper (CarService carService) { this .carService = carService; } @Override public void display () { System.out.println("CarServiceWrapper display before" ); carService.display(); System.out.println("CarServiceWrapper display after" ); } @Override public void run (URL url) { System.out.println("CarServiceWrapper run before" ); carService.run(url); System.out.println("CarServiceWrapper run after" ); } } public class CarServiceWrapper2 implements CarService { private CarService carService; public CarServiceWrapper2 (CarService carService) { this .carService = carService; } @Override public void display () { System.out.println("CarServiceWrapper2 display before" ); carService.display(); System.out.println("CarServiceWrapper2 display after" ); } @Override public void run (URL url) { System.out.println("CarServiceWrapper2 run before" ); carService.run(url); System.out.println("CarServiceWrapper2 run after" ); } }
配置类:
1 2 3 4 electric =cn.com.xiaocainiaoya.spi.dubbo.adaptive.ElectricCarServiceImpltank =cn.com.xiaocainiaoya.spi.dubbo.adaptive.TankCarServiceImplwrapper =cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarServiceWrapperwrapper2 =cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarServiceWrapper2
客户端:
1 2 3 4 5 6 7 8 9 10 11 public class CarMain { public static void main (String[] args) { ExtensionLoader<CarService> loader = ExtensionLoader.getExtensionLoader(CarService.class); CarService car = loader.getAdaptiveExtension(); URL url = URL.valueOf("xxx" ); car.run(url); } }
输出:
1 2 3 4 5 CarServiceWrapper2 run before CarServiceWrapper run before ElectricCarServiceImpl run CarServiceWrapper run after CarServiceWrapper2 run after
激活机制Activate 用于直接激活扩展类,通过一定的规则(分组)等方式,一下子激活符合条件的扩展类。
1 2 3 4 5 6 7 8 9 10 11 12 public @interface Activate { String[] group() default {}; String[] value() default {}; String[] before() default {}; String[] after() default {}; int order () default 0 ; }
before()
和after()
已经过时。
group:分组名称,根据组名称来激活一些类(是一个大范围,指定到一个集体)
value:指定一个名称,可以不根据分组,直接根据名称来激活(一个小范围,直接指定到个体)
order:排序号,序号越小,优先级越高,默认值为0。
定义接口:
1 2 3 4 5 6 7 8 @SPI("electric") public interface CarService { void display () ; void run (URL url) ; }
实现类:
3个具体实现类,其中HybridCarServiceImpl
既属于tankGroup
,也属于electricGroup
。
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 @Activate(group = "electricGroup") public class ElectricCarServiceImpl implements CarService { @Override public void display () { System.out.println("ElectricCarServiceImpl display" ); } @Override public void run (URL url) { System.out.println("ElectricCarServiceImpl run" ); } } @Activate(group = {"tankGroup", "electricGroup"}) public class HybridCarServiceImpl implements CarService { @Override public void display () { System.out.println("HybridCarServiceImpl display" ); } @Override public void run (URL url) { System.out.println("HybridCarServiceImpl run" ); } } @Activate(group = "tankGroup") public class TankCarServiceImpl implements CarService { @Override public void display () { System.out.println("TankCarServiceImpl display" ); } @Override public void run (URL url) { System.out.println("TankCarServiceImpl run" ); } }
配置:
1 2 3 electric =cn.com.xiaocainiaoya.spi.dubbo.adaptive.ElectricCarServiceImpltank =cn.com.xiaocainiaoya.spi.dubbo.adaptive.TankCarServiceImplhybrid =cn.com.xiaocainiaoya.spi.dubbo.adaptive.HybridCarServiceImpl
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public static void main (String[] args) { ExtensionLoader<CarService> loader = ExtensionLoader.getExtensionLoader(CarService.class); URL url = URL.valueOf("xxx" ); List<CarService> tankServices = loader.getActivateExtension(url, "" , "tankGroup" ); List<CarService> tankServices = loader.getActivateExtension(url, "tank" , "tankGroup" ); URL url = URL.valueOf("xxx?tank=true" ); List<CarService> tankServices = loader.getActivateExtension(url, "" , "tankGroup" ); for (CarService carService : tankServices) { carService.run(url); } } }
输出:
1 2 TankCarServiceImpl run HybridCarServiceImpl run
注: 我在@Activate
中只有指定了group
值,并没有指定value
。
1 2 3 4 5 6 7 8 9 10 11 12 @Activate(group = "tankGroup", value = "tank") @Activate(group = {"tankGroup", "electricGroup"}, value = "hybrid") @Activate(group = "electricGroup" , value = "electric") List<CarService> tankServices = loader.getActivateExtension(url, "" , "tankGroup" ); URL url = URL.valueOf("xxx?service.car=tank" ); List<CarService> tankServices = loader.getActivateExtension(url, "service.car" , "tankGroup" );
看看源码 根据前面提到的特性,我们需要通过一个类,来自动查找具体实现类,这个类就是ExtensionLoader
(在jdk
中是通过ServiceLoader
)。
这是一个静态方法,通过这个方法获取ExtensionLoader
实例。
1 ExtensionLoader<Car> loader = ExtensionLoader.getExtensionLoader(Car.class);
先从缓存中获取,如果获取不到,则创建一个新的ExtensionLoader
实例
1 2 3 4 5 6 7 8 9 10 11 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; }
来看一下这个类的构建函数:
1 2 3 4 5 6 7 8 9 private ExtensionLoader (Class<?> type) { this .type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
ExtensionFactory
的两个实现:从以下可以看出,这是为了兼容spring
,加载具体实现类可以从spring
上下文中获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class SpringExtensionFactory implements ExtensionFactory { private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>(); @SuppressWarnings("unchecked") public <T> T getExtension (Class<T> type, String name) { for (ApplicationContext context : contexts) { if (context.containsBean(name)) { Object bean = context.getBean(name); if (type.isInstance(bean)) { return (T) bean; } } } return null ; } }
拿到ExtensionLoader
实例之后,就可以执行上文中介绍的一些特性功能。
1 2 3 4 5 6 7 8 CarService car = loader.getExtension("electric" ); CarService car = loader.getAdaptiveExtension(); loader.getActivateExtension(url, "" , "tankGroup" );
具体实现类的获取过程:
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 getExtension (String name) { if (name == null || name.length() == 0 ) throw new IllegalArgumentException("Extension name == null" ); if ("true" .equals(name)) { return getDefaultExtension(); } Holder<Object> holder = cachedInstances.get(name); if (holder == null ) { cachedInstances.putIfAbsent(name, new Holder<Object>()); holder = cachedInstances.get(name); } Object instance = holder.get(); if (instance == null ) { synchronized (holder) { instance = holder.get(); if (instance == null ) { instance = createExtension(name); holder.set(instance); } } } return (T) instance; }
创建扩展类:
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 private T createExtension (String name) { Class<?> clazz = getExtensionClasses().get(name); if (clazz == null ) { throw findException(name); } try { T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null ) { EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } injectExtension(instance); Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && wrapperClasses.size() > 0 ) { 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 + ") could not be instantiated: " + t.getMessage(), 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 37 38 39 40 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; } private Map<String, Class<?>> loadExtensionClasses() { final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null ) { String value = defaultAnnotation.value(); if (value != null && (value = value.trim()).length() > 0 ) { String[] names = NAME_SEPARATOR.split(value); if (names.length > 1 ) { throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); } if (names.length == 1 ) cachedDefaultName = names[0 ]; } } Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY); loadFile(extensionClasses, DUBBO_DIRECTORY); loadFile(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; }
扩展类注入 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 T injectExtension (T instance) { try { if (objectFactory != null ) { for (Method method : instance.getClass().getMethods()) { if (method.getName().startsWith("set" ) && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { Class<?> pt = method.getParameterTypes()[0 ]; try { String property = method.getName().length() > 3 ? method.getName().substring(3 , 4 ).toLowerCase() + method.getName().substring(4 ) : "" ; Object object = objectFactory.getExtension(pt, property); if (object != null ) { method.invoke(instance, object); } } catch (Exception e) { logger.error("fail to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance; }
自适应扩展类 首先来看看自适应扩展类的相关源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public T getAdaptiveExtension () { Object instance = cachedAdaptiveInstance.get(); if (instance == null ) { if (createAdaptiveInstanceError == null ) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null ) { try { instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } } } } } return (T) instance; }
创建自适应扩展类:
1 2 3 4 5 6 7 8 private T createAdaptiveExtension () { try { return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e); } }
获取到自适应扩展类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private Class<?> getAdaptiveExtensionClass() { getExtensionClasses(); if (cachedAdaptiveClass != null ) { return cachedAdaptiveClass; } return cachedAdaptiveClass = createAdaptiveExtensionClass(); } private Class<?> createAdaptiveExtensionClass() { String code = createAdaptiveExtensionClassCode(); ClassLoader classLoader = findClassLoader(); com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
我这边测试的时候动态生成的一个自适应扩展类:
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 package cn.com.xiaocainiaoya.spi.dubbo.adaptive;import com.alibaba.dubbo.common.extension.ExtensionLoader;public class CarService $Adaptive implements cn .com .xiaocainiaoya .spi .dubbo .adaptive .CarService { public void display () { throw new UnsupportedOperationException("method public abstract void cn.com.xiaocainiaoya.spi.dubbo.adaptive" + ".CarService.display() of interface cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService is not " + "adaptive method!" ); } public void run (com.alibaba.dubbo.common.URL arg0) { if (arg0 == null ) throw new IllegalArgumentException("url == null" ); com.alibaba.dubbo.common.URL url = arg0; String extName = url.getParameter("car.service" , "electric" ); if (extName == null ) throw new IllegalStateException("Fail to get extension(cn.com.xiaocainiaoya.spi.dubbo.adaptive" + ".CarService) name from url(" + url.toString() + ") use keys([car.service])" ); cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService extension = (cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService) ExtensionLoader.getExtensionLoader(cn.com.xiaocainiaoya.spi.dubbo.adaptive.CarService.class).getExtension(extName); extension.run(arg0); } }
自动激活机制 1 2 3 4 5 6 7 ExtensionLoader<CarService> loader = ExtensionLoader.getExtensionLoader(CarService.class); URL url = URL.valueOf("xxx" ); List<CarService> tankServices = loader.getActivateExtension(url, "" , "tankGroup" ); for (CarService carService : tankServices) { carService.run(url); }
获取需要自动激活的实现类:
1 2 3 4 public List<T> getActivateExtension (URL url, String key, String group) { String value = url.getParameter(key); return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group); }
获取自动激活的实现类:
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 List<T> getActivateExtension (URL url, String[] values, String group) { List<T> exts = new ArrayList<T>(); List<String> names = values == null ? new ArrayList<String>(0 ) : Arrays.asList(values); if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { getExtensionClasses(); for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); if (isMatchGroup(group, activate.group())) { T ext = getExtension(name); if (!names.contains(name) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name) && isActive(activate, url)) { exts.add(ext); } } } Collections.sort(exts, ActivateComparator.COMPARATOR); } List<T> usrs = new ArrayList<T>(); for (int i = 0 ; i < names.size(); i++) { String name = names.get(i); if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { if (Constants.DEFAULT_KEY.equals(name)) { if (usrs.size() > 0 ) { exts.addAll(0 , usrs); usrs.clear(); } } else { T ext = getExtension(name); usrs.add(ext); } } } if (usrs.size() > 0 ) { exts.addAll(usrs); } return exts; }
目前按我理解:自动激活机制的意思是,会将整个组都激活(加载),但是接口会根据相应的规则来获取对应的扩展类。(比如groupA下有V1,V2,V3,groupB下有W1,W2,W3,如果是加载groupA,那么V1,V2,V3都会激活,但是会根据一些规则判断,返回其中的某个或者某些,比如只返回V1,或者返回V1,V2)