Dubbo之扩展机制深入分析
dubbo版本
- dubbo版本2.6.7
扩展点特性
-
自动包装(Wrapper):
ExtensionLoader在加载扩展时,如果发现这个扩展类包含其他扩展点作为构造函数的参数,则这个扩展类就会被认为是Wrapper类。例如Protocol接口默认就包含ProtocolFilterWrapper、ProtocolListenerWrapper、QosProtocolWrapper三个增强Wrapper实现类//继承Protocol接口,并且构造函数传入Protocol类型(装饰模式,增强实现类),被认定为Wrapper类 //还有诸如ProtocolListenerWrapper、QosProtocolWrapper的类 public class ProtocolFilterWrapper implements Protocol { private final Protocol protocol; public ProtocolFilterWrapper(Protocol protocol) { if (protocol == null) { throw new IllegalArgumentException("protocol == null"); } this.protocol = protocol; } ...省略... } -
自动加载:如果某个扩展类是另一个扩展类的成员变量,并且拥有setter方法,框架会自动注入对应的扩展实例。如果成员变量是一个接口(可能有多个实现),此时应该注入哪个实现呢?
-
自适应适配器:通过
@Adaptive动态通过URL中的参数来确定使用哪个实现类。当外部调用Transporter#bind方法时,会动态从传入的URL中提取出key为Constants.SERVER_KEY的值,如果能匹配某个扩展实现类则直接使用。如果不能匹配上,则继续提取Constants.TRANSPORTER_KEY的值,如果还是未匹配上,则抛出异常。即@Adaptive传入多个参数,依次进行实现类的匹配,直到抛出异常。@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Adaptive { String[] value() default {}; } @SPI("netty") public interface Transporter { @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY}) Server bind(URL url, ChannelHandler handler) throws RemotingException; @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY}) Client connect(URL url, ChannelHandler handler) throws RemotingException; } -
自动激活:如果需要多个实现类同时被激活,比如Filter可以有多个同时使用,或者根据条件不同,同时激活多个实现类,可以使用
@Activate注解。该注解可以标记对应的扩展点为默认激活状态,还可以通过传入不同的参数,设置扩展点在不同条件下被自动激活@Activate(group = {Constants.CONSUMER, Constants.PROVIDER}, value = Constants.CACHE_KEY) public class CacheFilter implements Filter{ } -
dubbo扩展点主要在
com.alibaba.dubbo.common.extension包下,结构如下com.alibaba.dubbo.common.extension . ├── Activate.java ├── Adaptive.java ├── DisableInject.java ├── ExtensionFactory.java ├── ExtensionLoader.java ├── SPI.java ├── factory │ ├── AdaptiveExtensionFactory.java │ └── SpiExtensionFactory.java └── support └── ActivateComparator.java com.alibaba.dubbo.config.spring.extension . └── SpringExtensionFactory.java
注解
@SPI
-
@SPI可以使用在类、接口和枚举上。主要作用就是标记接口是一个Dubbo SPI接口,即一个扩展点,可以有多个实现。value属性表示接口的默认实现类对应的Key(在配置文件中)@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface SPI { /** * default extension name */ String value() default ""; }
@Adaptive
-
@Adaptive可以标记在类、接口、枚举和方法上。如果标记在接口方法上,则可以通过参数动态获得实现类。在第一次getExtension时,会自动生成和编译一个动态的Xxx$Adaptive类,从而达到动态实现类的效果@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Adaptive { String[] value() default {}; } -
@Adaptive:该注解可以注解在两个地方-
实现类上:例如AdaptiveExtensionFactory(该类不是工厂类,有特殊的逻辑) AdaptiveCompiler(实际上也是工厂类,但是不能靠动态生成,否则会形成死循环),ExtensionLoader需要依赖他们工作,所以得使用此方式
-
接口的方法上:会动态生成相应的动态类(实际上是一个工厂类,工厂设计模式),例如
Protocol$Adapter。ExtensionLoader根据接口定义动态的生成适配器代码,并实例化这个生成的动态类。被@Adaptive注解的方法会生成具体的方法实现。没有注解的方法生成的实现都是抛UnsupportedOperationException。被注解的方法在生成的动态类中,会根据url里的参数信息,来决定实际调用哪个扩展。
-
@Activate
-
@Activate可以标记在类、接口、枚举、方法上。主要用于有多个扩展点实现类同时被激活、根据不同的条件激活不同的实现类@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Activate { //url分组匹配则激活,如果没有设置则不过滤 String[] group() default {}; //url包含指定的key则激活,没有设置则不过滤 String[] value() default {}; //哪些扩展点在当前扩展点之前 String[] before() default {}; //哪些扩展点在当前扩展点之后 String[] after() default {}; //排序 int order() default 0; }
ExtensionLoader
-
ExtensionLoader没有提供public的构造方法,通过静态方法getExtensionLoader获取ExtensionLoader实例。从源码可以看出,类型必须是接口,而且接口必须通过@SPI修饰。每一个扩展点都会对应一个ExtensionLoaderprivate ExtensionLoader(Class<?> type) { //扩展点接口类型 this.type = type; //非ExtensionFactory类型返回的是一个AdaptiveExtensionFactory objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); } 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 interface!"); } //接口是否有@SPI注解 if (!withExtensionAnnotation(type)) { throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!"); } //如果缓存中不存在,则创建一个新的实例 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; }
getExtension
-
getExtension(String name):根据名称返回一个扩展点实现类,是整个扩展类加载器(ExtensionLoader)最为核心的方法。- 从指定目录中(
META-INF/dubbo/internal/META-INF/service/META-INF/dubbo/)加载所有扩展实现类并缓存(仅仅缓存class对象) - 根据传入的名称初始化扩展实现类的实例,并缓存
- 遍历扩展实现类的所有方法
- 查找public setter方法(参数仅仅为1),自动注入扩展实现类实例
- 查找包含与扩展点类型相同的构造函数的Wrapper类,注入扩展实现类实例,并初始化Wrapper类。使用
@DisableInject注解修饰的方法不注入,返回Wrapper类实例
- 如果不存在Wrapper类,返回扩展实现类实例,如果存在返回Wrapper类实例
- 从指定目录中(
-
主要流程
![getExtension主要流程]()
-
源码流程大致
getExtension(String name) 如果缓存中存在则读取,否则创建 => createExtension(name) 创建 => getExtensionClasses().get(name) 从配置目录加载配置并创建扩展实现类的Class => injectExtension(instance) # 注入当前实例依赖的其他扩展点实例 => injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))实例化wrapper并注入扩展实现类 -
getExtension:判断缓存中是否存在,如果不存在则创建public T getExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); //如果为true则调用默认的扩展实现 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; } -
createExtension:从配置文件中加载配置创建Class并缓存private T createExtension(String name) { //从配置文件中加载配置Class实例 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, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } //检查是否依赖其他扩展类,如果依赖其他扩展实现类则注入 injectExtension(instance); //创建Wrapper实例,构造注入依赖的类 Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && !wrapperClasses.isEmpty()) { 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); } } -
getExtensionClasses:从目录中加载配置信息,通过Class.forName创建Class,并保存在缓存中。如果实现类的构造方法是扩展点接口类型,则表示实现类是一个增强包装类(Wrapper)类,将Wrapper类保存到Set中。为什么Wrapper不指定顺序呢?:第一Class的加载顺序不确定,第二Wrapper主要用于增强处理,顺序没有影响。所以在自己实现Wrapper时一定要注意必须与顺序无关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; } // synchronized in getExtensionClasses private Map<String, Class<?>> loadExtensionClasses() { //检查是否有@SPI注解 final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { String value = defaultAnnotation.value(); if ((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<?>>(); loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); loadDirectory(extensionClasses, DUBBO_DIRECTORY); loadDirectory(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; } private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) { String fileName = dir + type.getName(); 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 when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } } private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8")); try { String line; //每次处理一行 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(); line = line.substring(i + 1).trim(); } if (line.length() > 0) { //加载扩展类的实现 loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name); } } 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); } } } } finally { reader.close(); } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", class file: " + resourceURL + ") in " + resourceURL, t); } } 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 when load extension class(interface: " + type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + "is not subtype of interface."); } //如果实现类是@Adaptive类型的,会赋值给cachedAdaptiveClass,这个用来存放被@Adaptive注解的实现类 if (clazz.isAnnotationPresent(Adaptive.class)) { if (cachedAdaptiveClass == null) { cachedAdaptiveClass = clazz; } else if (!cachedAdaptiveClass.equals(clazz)) { throw new IllegalStateException("More than 1 adaptive class found: " + cachedAdaptiveClass.getClass().getName() + ", " + clazz.getClass().getName()); } } else if (isWrapperClass(clazz)) { //构造方法参数是扩展点类型的,就是一个Wrapper类 Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { //cachedWrapperClasses用来存放当前扩展点实现类中的包装类 //因为class的加载顺序是未知的,所以使用Set保存,即应当确保wrapper的实现与顺序无关 cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } else { clazz.getConstructor(); if (name == null || name.length() == 0) { 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 (names != null && names.length > 0) { Activate activate = clazz.getAnnotation(Activate.class); if (activate != null) { cachedActivates.put(names[0], activate); } for (String n : names) { if (!cachedNames.containsKey(clazz)) { cachedNames.put(clazz, n); } Class<?> c = extensionClasses.get(n); if (c == null) { extensionClasses.put(n, clazz); } else if (c != clazz) { throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName()); } } } } } private boolean isWrapperClass(Class<?> clazz) { try { clazz.getConstructor(type); return true; } catch (NoSuchMethodException e) { return false; } } -
injectExtension:扩展点注入,通过反射获取类的所有方法,遍历setter方法,并得到参数类型。通过ExtensionFactory寻找参数类型相同的扩展类实例,如果找到就通过反射注入。private T injectExtension(T instance) { try { if (objectFactory != null) { for (Method method : instance.getClass().getMethods()) { //public setter 并且只有一个参数 if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { /** * Check {@link DisableInject} to see if we need auto injection for this property */ if (method.getAnnotation(DisableInject.class) != null) { continue; } //获取当前实例setter方法的参数 Class<?> pt = method.getParameterTypes()[0]; try { //获取小写开头的名称,setUserInterface 变为userInterface String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; //参数类型如果与扩展点匹配,则调用setter方法注入 Object object = objectFactory.getExtension(pt, property); if (object != null) { //setter方法注入 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; }
getAdaptiveExtension
-
getAdaptiveExtension:获取自适应扩展类,在Dubbo中每一个扩展接口都有一个对应的适配器类Xxx$Adaptive(动态生成的)- 从配置中加载配置信息
- 如果实现扩展类被
@Adaptive修饰,则直接使用此实现类,只能有一个实现类被@Adaptive修饰。如果没有被@Adaptive修饰,则自动生成接口$Adaptive形式的类源码,获取类加载器和编译器,编译生成的源码 - 注入其他扩展类实现
- 返回对应的自适应实例
-
主要流程
![getAdaptiveExtension主要流程]()
-
源码主要逻辑
getAdaptiveExtension() => getAdaptiveExtensionClass 加载所有实现类,如果实现类有被标为@Adaptive的则返回,否则生成【接口$Adaptive】类 =>injectExtension(instance) 注入实现类或者生成的类 -
getAdaptiveExtension判断缓存中是否已存在,存在则返回,否则创建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); } catch (Throwable t) { createAdaptiveInstanceError = t; throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t); } } } } else { throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } } return (T) instance; } -
createAdaptiveExtension:创建自适应实现类private T createAdaptiveExtension() { try { //(T) getAdaptiveExtensionClass().newInstance()类似cn.jannal.spi.UserInterface$Adaptive return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e); } } -
getAdaptiveExtensionClass:获取自适应实现类,如果实现类中没有标记@Adaptive注解的,就生成一个【接口名$Adaptive】的类private Class<?> getAdaptiveExtensionClass() { //加载所有实现,如果有@Adaptive类型,则会赋值为cachedAdaptiveClass属性缓存起来 getExtensionClasses(); if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } //如果没有找到@Adaptive修饰的实现类,则自动生成一个 //生成的类名称类似cn.jannal.spi.UserInterface$Adaptive return cachedAdaptiveClass = createAdaptiveExtensionClass(); } -
createAdaptiveExtensionClass:组装自适应类的源代码,并编译。组装与编译在后面详细介绍private Class<?> createAdaptiveExtensionClass() { //组装自适应扩展点类的源代码 String code = createAdaptiveExtensionClassCode(); //使用AppClassloader加载 ClassLoader classLoader = findClassLoader(); //获取编译器,默认使用javassist com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); //编译源码为Class对象 return compiler.compile(code, classLoader); } -
injectExtension:注入依赖的扩展点实现,上面已经分析过
生成源代码逻辑
-
源代码
@SPI("userImpl") public interface UserInterface { //指定默认实现 @Adaptive({"userImpl"}) public void run(URL url); } -
组装后的代码,根据url中的参数获取扩展名字,如果url中没有就使用默认的扩展名,然后根据扩展名去获取具体的实现
package cn.jannal.spi; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class UserInterface$Adaptive implements cn.jannal.spi.UserInterface { 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("userImpl", "userImpl"); if (extName == null) { throw new IllegalStateException( "Fail to get extension(cn.jannal.spi.UserInterface) name from url(" + url.toString() + ") use keys([userImpl])"); } cn.jannal.spi.UserInterface extension = (cn.jannal.spi.UserInterface) ExtensionLoader .getExtensionLoader(cn.jannal.spi.UserInterface.class) .getExtension(extName); extension.run(arg0); } } 如果 @Adaptive({"userImpl"})没有指定默认值,比如 @Adaptive public void run(URL url); 则生成的代码如下,即实现的名称为user.interface com.alibaba.dubbo.common.URL url = arg0; String extName = url.getParameter("user.interface", "userImpl"); -
如果一个接口上既有
@SPI("userImpl")注解,又有@Adaptive("userImpl2")注解,则最终生成的代码是url.getParameter("userImpl2", "userImpl")。即优先通过@Adaptive("userImpl2")传入的key去找默认实现类,如果没找到,则通过@SPI("userImpl")中的key去查找。如果@SPI注解没有默认值,则把类名转换为key再去查找 -
源码生成主要逻辑
-
校验:接口的所有方法必须有一个方法由
@Adaptive注解修饰 -
生成package(与接口同一个报名)、import(导入ExtensionLoader类)、类名(
UserInterface$Adaptive)。其他类调用全部使用全限定名,这样就不需import了 -
遍历接口所有方法,如果方法没有
@Adaptive修饰,则默认抛出UnsupportedOperationException。生成参数校验信息 -
生成默认实现的名称:如果
@Adaptive没有指定默认值,获取接口名的SimpleName,不断查找大写字母,并通过.分隔,得到默认的实现类名。比如接口UserInterface会转换为user.interface -
生成获取扩展点名称的代码:根据
@Adaptive中配置的key值生成。比如1. @Adaptive({"userImpl"}) 生成 String extName = url.getParameter("userImpl", "userImpl"); 2. @Adaptive({"protocol"}) 生成 String extName = url.getProtocol(); -
生成获取扩展实现类的代码
ExtensionLoader .getExtensionLoader(cn.jannal.spi.UserInterface.class) .getExtension(extName);
-
编译源代码
-
编译源代码生成一个Class。
Compiler也是一个SPI接口,@Adaptive注解修饰AdaptiveCompiler,表示AdaptiveCompiler就是编译器的默认实现类,不需要再自动生成(每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive注释的,那么dubbo会动态生成一个自适应实现类(接口名称$Adaptive)) -
继承实现图
![Compiler继承图]()
-
AdaptiveCompiler:有@Adaptive注解,说明此类是默认实现,与AdaptiveExtensionFactory作用相似,都是为了管理具体的实现。//表示默认实现是javassist @SPI("javassist") public interface Compiler { Class<?> compile(String code, ClassLoader classLoader); } @Adaptive public class AdaptiveCompiler implements Compiler { private static volatile String DEFAULT_COMPILER; //在ApplicationConfig中设置默认编译器,即通过标签<dubbo:application compiler="jdk"> public static void setDefaultCompiler(String compiler) { DEFAULT_COMPILER = compiler; } @Override public Class<?> compile(String code, ClassLoader classLoader) { Compiler compiler; ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class); String name = DEFAULT_COMPILER; // copy reference if (name != null && name.length() > 0) { compiler = loader.getExtension(name); } else { compiler = loader.getDefaultExtension(); } return compiler.compile(code, classLoader); } } -
AbstractCompiler封装一些通用的校验- 正则匹配包名和类名,并拼写出类的全限定名称
- 尝试通过Class.forName加载类,如果已经存在,则无需再次编译。如果不捕获
ClassNotFoundException异常,并调用子类的doCompile方法实现源代码编译
getActivateExtension
getActivateExtension:获取自动激活的扩展类,根据不同的条件同时激活多个扩展普通实现类
- 遍历
@Activate注解集合,根据传入URL匹配条件(group和name等)得到所有符合条件的扩展实现类。如果url参数重传入-default,则都不被激活。如果传入的扩展名以-开头,则也不被激活 - 根据
@Activate配置的before、after、order等参数进行排序 - 遍历所有自定义的扩展类名称,更具用户URL配置的顺序,调整扩展点激活顺序。
-
主要流程
![]()
-
案例
@SPI("AImpl") public interface AInterface { public void println(String info); } @Activate(value = {"valueA"}, group = {"group1"}) public class AInterfaceImpl implements AInterface { @Override public void println(String info) { System.out.println("B:" + info); } } @Activate(value = {"valueB"}, group = {"group1"}) public class BInterfaceImpl implements AInterface { @Override public void println(String info) { System.out.println("B:" + info); } } 创建文件 src/main/resources/META-INF/dubbo/internal/cn.jannal.spi.activate.AInterface AImpl=cn.jannal.spi.activate.AInterfaceImpl BImpl=cn.jannal.spi.activate.BInterfaceImpl public class Main { @Test public void testActivate() { ExtensionLoader<AInterface> extensionLoader = ExtensionLoader.getExtensionLoader(AInterface.class); URL url = URL.valueOf("test://localhost/test"); url = url.addParameter(Constants.GROUP_KEY, "group1"); url = url.addParameter("ext", "valueB"); //url url中的key 匹配的组名称 //test://localhost/test?ext=valueB&group=group1 List<AInterface> interfaces = extensionLoader.getActivateExtension(url, "ext", "group1"); //[cn.jannal.spi.activate.BInterfaceImpl@1f89ab83] System.out.println(interfaces); //B:jannal for (AInterface aInterface : interfaces) { aInterface.println("jannal"); } } } -
源码分析
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); } 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); //-default if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { getExtensionClasses(); //遍历缓存中所有标记@Activate的实现类 for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); //如果group为null返回true if (isMatchGroup(group, activate.group())) { T ext = getExtension(name); //排除指定的names扩展,name是配置文件扩展的key,names是url中指定key的values // test://localhost/test?ext=valueB&group=group1 //启动name是BImpl(配置文件实现类的key),names是valueB(接口实现Activate中的value) 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.isEmpty()) { exts.addAll(0, usrs); usrs.clear(); } } else { T ext = getExtension(name); usrs.add(ext); } } } if (!usrs.isEmpty()) { exts.addAll(usrs); } return exts; } private boolean isMatchGroup(String group, String[] groups) { if (group == null || group.length() == 0) { return true; } if (groups != null && groups.length > 0) { for (String g : groups) { if (group.equals(g)) { return true; } } } return false; } private boolean isActive(Activate activate, URL url) { String[] keys = activate.value(); //如果Active注解的value没有配置,表示不需要条件都可以使用 if (keys.length == 0) { return true; } for (String key : keys) { for (Map.Entry<String, String> entry : url.getParameters().entrySet()) { String k = entry.getKey(); String v = entry.getValue(); //判断url中的key是否与active中value的值一致 if ((k.equals(key) || k.endsWith("." + key)) && ConfigUtils.isNotEmpty(v)) { return true; } } } return false; }
ExtensionFactory
-
ExtensionFactory主要用于加载扩展的实现。本身也通过@SPI修饰@SPI public interface ExtensionFactory { <T> T getExtension(Class<T> type, String name); } -
ExtensionFactory有三个实现类,不同的实现可以以不同的方式来完成扩展点实现的加载![]()
-
AdaptiveExtensionFactory被@Adaptive注解注释,意味着它就是ExtensionFactory对应的自适应扩展实现。因为每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive注释的,那么dubbo会动态生成一个自适应实现类(接口名称$Adaptive)@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; } } -
SpiExtensionFactory:判断是否是接口,接口是否被@SPI注解修饰。如果包含,返回自适应实现类(默认类名为接口名$Adaptive)public class SpiExtensionFactory implements ExtensionFactory { @Override public <T> T getExtension(Class<T> type, String name) { //判断是接口并且存在@SPI注解 if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { //获得扩展加载器 ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type); if (!loader.getSupportedExtensions().isEmpty()) { //返回适配器类的对象 return loader.getAdaptiveExtension(); } } return null; } }
总结
- 每一个扩展点都会对应一个
ExtensionLoader实例,扩展类型必须是接口而且必须使用@SPI修饰 @Adaptive注解要么注释在扩展点@SPI的方法上,要么注释在其实现类的类定义上。在实现类上定义表示显示指定自适应实现类,否则生成一个【接口名$Adaptive】 的实现类- 如果
@Adaptive注解注释在@SPI接口的方法上,没有标记的方法自动生成的实现中默认为注解的方法抛异常 - 每个扩展点可以有多个可自动激活的扩展点实现(使用
@Activate注解) - 如果扩展点有多个Wrapper,那么最终其执行的顺序不确定(内部使用
ConcurrentHashSet存储)





浙公网安备 33010602011771号