dubbo源码分析01:SPI机制
一、什么是spi
1.1.jdk spi示例
1 public interface robot { 2 void sayhello(); 3 } 4 5 public class optimusprime implements robot { 6 7 @override 8 public void sayhello() { 9 system.out.println("hello, i am optimus prime."); 10 } 11 } 12 13 public class bumblebee implements robot { 14 15 @override 16 public void sayhello() { 17 system.out.println("hello, i am bumblebee."); 18 } 19 }
接下来,在项目(以一个典型的maven项目为例)的“resources/meta-inf/services”路径下创建一个文件,名称为robot的全限定名“org.apache.spi.robot”。文件内容如下:
org.apache.spi.optimusprime org.apache.spi.bumblebee
编写测试代码,运行之后可以看到两个实现类被加载并调用了sayhello方法(调用结果演示略)。
public class javaspitest { @test public void sayhello() throws exception { serviceloader<robot> serviceloader = serviceloader.load(robot.class); system.out.println("java spi"); serviceloader.foreach(robot::sayhello); } }
1.2.dubbo spi示例
//使用spi注解标注的接口 @spi public interface robot { void sayhello(); }
接下来,在项目(以一个典型的maven项目为例)的“resources/meta-inf/dubbo”路径下创建一个文件,名称为robot的全限定名“org.apache.spi.robot”。文件内容如下:
optimusprime=org.apache.spi.optimusprime bumblebee=org.apache.spi.bumblebee
//测试类 public class dubbospitest { @test public void sayhello() throws exception { //传入一个标注有@spi的接口class,通过getextensionloader获取该spi接口的extensionloader实例 extensionloader<robot> extensionloader = extensionloader.getextensionloader(robot.class); //传入要获取的实现类的name(meta-inf/dubbo/org.apache.spi.robot文件下的name),获取实现类实例 robot optimusprime = extensionloader.getextension("optimusprime"); optimusprime.sayhello(); robot bumblebee = extensionloader.getextension("bumblebee"); bumblebee.sayhello(); } }
通过与jdk spi示例的比较,发现dubbo spi与jdk spi最大的不同就是dubbo spi通过键值对的方式进行配置。这样最大的好处是可以按需加载指定的实现类(通过name指定)。下面就让我们以本例中getextensionloader与getextension两个方法作为引子,分析dubbo spi的实现源码。
二、getextensionloader
/**************************************** 相关字段 ****************************************/ //extensionloader对应的spi接口类型 private final class<?> type; //extensionloader对应的extensionfactory实例 private final extensionfactory objectfactory; //extensionloader全局缓存,key为spi接口类型,value为相应的extensionloader实例 private static final concurrentmap<class<?>, extensionloader<?>> extension_loaders = new concurrenthashmap<>(); /**************************************** 相关方法 ****************************************/ /** * 静态方法,根据spi接口类型获取相应的extensionloader */ public static <t> extensionloader<t> getextensionloader(class<t> type) { //判断type是否为空、是否是接口类型、是否具有@spi注解 if (type == null) { throw new illegalargumentexception("extension type == null"); } if (!type.isinterface()) { throw new illegalargumentexception("extension type (" + type + ") is not an interface!"); } if (!withextensionannotation(type)) { throw new illegalargumentexception("extension type (" + type + ") is not an extension..."); } //从extensionloader的缓存中根据spi接口类型获取对应的extensionloader实例 extensionloader<t> loader = (extensionloader<t>) extension_loaders.get(type); //若缓存没有该实例,则new一个,并且存放入缓存,key为type if (loader == null) { extension_loaders.putifabsent(type, new extensionloader<t>(type)); loader = (extensionloader<t>) extension_loaders.get(type); } return loader; } /** * 私有构造器,对调用者而言,只能通过getextensionloader方法获取extensionloader实例 */ private extensionloader(class<?> type) { //保存该extensionloader的spi接口类型信息 this.type = type; //若spi接口类型为extensionfactory,则不设置字段extensionfactory, //否则需要设置一个extensionfactory。具体的获取逻辑我们后面会讲到 objectfactory = (type == extensionfactory.class ? null : extensionloader.getextensionloader(extensionfactory.class).getadaptiveextension()); }
三、getextension
/**************************************** 实例缓存相关字段 ****************************************/ //全部spi接口的扩展类实例缓存,key为扩展类class(每一个spi接口的每一个实现类的class都不同) //value为对应的扩展类实例。注意该缓存要与另外一个类似的缓存cachedinstances区分开。 private static final concurrentmap<class<?>, object> extension_instances = new concurrenthashmap<>(); //每个extensionloader对应的spi接口的扩展类实例缓存, //key为扩展类的name,value为holder对象,其持有/维护扩展类的实例。 private final concurrentmap<string, holder<object>> cachedinstances = new concurrenthashmap<>(); /**************************************** class缓存相关字段 ****************************************/ //每个extensionloader对应的spi接口的扩展类class缓存,key为扩展类的name,value为扩展类class private final holder<map<string, class<?>>> cachedclasses = new holder<>(); //spi接口的扩展类中具有@adaptive注解的扩展类class缓存 private volatile class<?> cachedadaptiveclass = null; //spi接口的扩展类中被判定为具有包装功能的扩展类class缓存 private set<class<?>> cachedwrapperclasses; //spi接口的扩展类中具有@activate注解的缓存,key是扩展类names[0],value为@activate的class private final map<string, object> cachedactivates = new concurrenthashmap<>(); /**************************************** name缓存相关字段 ****************************************/ //spi接口的扩展类的name缓存,key为扩展类的class,value为扩展类的names[0] private final concurrentmap<class<?>, string> cachednames = new concurrenthashmap<>(); //spi接口的默认扩展类的name private string cacheddefaultname; /**************************************** 其他相关字段 ****************************************/ //extensionloader对应的spi接口class private final class<?> type; /**************************************** 相关方法 ****************************************/ /** * 获取extensionloader对应的spi接口的扩展类实例 */ public t getextension(string name) { //检查扩展类的name if (stringutils.isempty(name)) { throw new illegalargumentexception("extension name == null"); } //如果传入的name值为true,则获取默认的spi接口扩展类实例 if ("true".equals(name)) { return getdefaultextension(); } //getorcreateholder方法比较简单,它从缓存“cachedinstances”中获取该name对应的holder实例, //holder是一个“持有类”,其可能持有扩展类实例 holder<object> holder = getorcreateholder(name); object instance = holder.get(); //如果未获取到实例,在监视器锁中进行第二次获取与创建 if (instance == null) { synchronized (holder) { instance = holder.get(); if (instance == null) { //创建name对应的扩展类实例,并缓存到cachedinstances中 instance = createextension(name); holder.set(instance); } } } return (t) instance; } /** * 获取默认的扩展类实例 */ public t getdefaultextension() { //调用getextensionclasses方法获取spi接口配置的扩展类信息,返回结果为一个map<string, class>, //其中key为扩展类name,value为该name对应的扩展类class。 getextensionclasses(); //如果spi接口默认扩展类name为空或者为true,则默认的扩展类实例为null if (stringutils.isblank(cacheddefaultname) || "true".equals(cacheddefaultname)) { return null; } //否则调用getextension根据默认的扩展类name去获取实例 return getextension(cacheddefaultname); } /** * 创建一个扩展类的实例 */ private t createextension(string name) { //调用getextensionclasses方法,从返回结果中获取name对应的扩展类class,如果class为null,则抛出异常 class<?> clazz = getextensionclasses().get(name); if (clazz == null) { throw findexception(name); } try { //从缓存“extension_instances”中根据扩展类class获取实例 t instance = (t) extension_instances.get(clazz); if (instance == null) { //缓存未命中则通过反射创建一个实例,并存入缓存 extension_instances.putifabsent(clazz, clazz.newinstance()); instance = (t) extension_instances.get(clazz); } //向这个扩展类实例注入其所需要的属性(以setxxx为准),该方法比较复杂,我们后面会进行分析 injectextension(instance); //获取spi接口扩展类中具有包装功能的扩展类class缓存,然后对instance进行层层包装(装饰器模式), //对每次包装出来的新实例进行属性注入,全部包装完成后让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 ... couldn't be instantiated: "); } } /** * 获取spi接口配置的扩展类信息 */ private map<string, class<?>> getextensionclasses() { //从缓存“cachedclasses”中获取已加载的扩展类 map<string, class<?>> classes = cachedclasses.get(); if (classes == null) { synchronized (cachedclasses) { classes = cachedclasses.get(); if (classes == null) { //缓存为空,调用loadextensionclasses方法加载spi接口配置的扩展类信息,并缓存结果 classes = loadextensionclasses(); cachedclasses.set(classes); } } } return classes; } /** * 加载spi接口配置的扩展类信息 */ private map<string, class<?>> loadextensionclasses() { //获取spi接口默认扩展类的name并进行缓存 cachedefaultextensionname(); //读取并解析spi接口的配置文件,去几个固定的目录下读取 //(1):meta-inf/services/spi接口全限定类名(或spi接口全限定类名替换org.apache为com.alibaba) //(2):meta-inf/dubbo/spi接口全限定类名(或spi接口全限定类名替换org.apache为com.alibaba) //(3):meta-inf/dubbo/internal/spi接口全限定类名(或spi接口全限定类名替换org.apache为com.alibaba) 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; } /** * 获取spi接口默认扩展类的name并进行缓存 */ private void cachedefaultextensionname() { //获取extensionloader对应的spi接口上的spi注解 final spi defaultannotation = type.getannotation(spi.class); if (defaultannotation != null) { //获取spi注解的value值并进行校验 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 ..."); } if (names.length == 1) { //将其作为spi接口默认扩展类的name并进行缓存 cacheddefaultname = names[0]; } } } } /** * 加载spi接口的配置文件 */ 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) { //遍历获取到的url,并调用loadresource去加载资源 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: ..."); } } /** * 在loaddirectory的基础上,对每个文件中的内容进行加载与解析 */ private void loadresource(map<string, class<?>> extensionclasses, classloader classloader, java.net.url resourceurl) { try { try (bufferedreader reader = new bufferedreader(new inputstreamreader(resourceurl.openstream(), standardcharsets.utf_8))) { 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; //按“=”号截取name和扩展类的全限定类名,可以看出name是可以没有的 int i = line.indexof('='); if (i > 0) { name = line.substring(0, i).trim(); line = line.substring(i + 1).trim(); } //如果line,即扩展类全限定类名不为空,通过class.forname获取其class, //然后调用loadclass继续加载该class if (line.length() > 0) { loadclass(extensionclasses, resourceurl, class.forname(line, true, classloader), name); } } catch (throwable t) { illegalstateexception e = new illegalstateexception("failed to load ..."); exceptions.put(line, e); } } } } } catch (throwable t) { logger.error("exception occurred when loading extension class (interface: ..."); } } /** * 在loadresource的基础上,对文件中的每行获取到的class进行分析,并进行缓存 */ private void loadclass(map<string, class<?>> extensionclasses, java.net.url resourceurl, class<?> clazz, string name) throws nosuchmethodexception { //判断配置的扩展类是否为指定spi接口的实现类 if (!type.isassignablefrom(clazz)) { throw new illegalstateexception("error occurred when loading ... is not subtype of interface."); } if (clazz.isannotationpresent(adaptive.class)) { //若扩展类有@adaptive注解,将这个class存入缓存“cachedadaptiveclass” //注意:一个spi接口配置文件中,只能配置一个有@adaptive注解的扩展类 cacheadaptiveclass(clazz); } else if (iswrapperclass(clazz)) { //若扩展类具有clazz.getconstructor(type)这样的构造器,则认为其是一个具有包装功能的扩展类, //并将其存入缓存“cachedwrapperclasses”,一个spi接口可以配置多个用于包装的扩展类 cachewrapperclass(clazz); } else { //进入到这个分支,表示该class只是一个普通的spi接口扩展类。 //判断该扩展类是否具有无参构造器 clazz.getconstructor(); //如果该扩展类在spi接口配置文件中未定义name,则判断扩展类是否具有@extension注解, //如果有,则以@extension的value值作为name;否则以扩展类的simplename作为name, //并且,如果扩展类的simplename以spi接口的simplename作为后缀结尾,则name需要去掉该后缀 if (stringutils.isempty(name)) { name = findannotationname(clazz); if (name.length() == 0) { throw new illegalstateexception("no such extension name for the class ..."); } } //对name按照","进行分割 string[] names = name_separator.split(name); if (arrayutils.isnotempty(names)) { //names不为空 //若扩展类具有@activate注解,则使用names数组的第一个元素作为key,@activate的class为value //将映射关系存入缓存“cachedactivates” cacheactivateclass(clazz, names[0]); for (string n : names) { //将该扩展类的name和class存入缓存“cachednames”,name保持为names[0] cachename(clazz, n); //将该扩展类的name和class存入方法参数extensionclasses saveinextensionclass(extensionclasses, clazz, name); } } } }
通过以上的源码分析,我们了解到getextension方法获取一个spi接口的扩展类实例的流程分为解析配置文件、加载并缓存扩展类、创建并加工扩展类实例几个步骤。
在得到一个最终可用的扩展类实例前,该实例会进行属性注入与层层包装,这些行为在官网上被成为扩展点特性,这里我们把它称之为“扩展类特性”。官方给出了4个特性,分别为“扩展点自动包装”、“扩展点自动装配”、“扩展点自适应”以及“扩展点自动激活”。在下面的其余章节中,我们将重点来研究这几个扩展点特性。
四、扩展点自适应
4.1.什么是自适应扩展类
/** * 一个模拟的spi接口 */ @spi public interface wheelmaker { wheel makewheel(url url); } /** * spi接口的自适应扩展类 */ public class adaptivewheelmaker implements wheelmaker { //自适应扩展类该方法的逻辑为通过url中的参数,动态的获取真正需要执行的spi接口扩展类 public wheel makewheel(url url) { if (url == null) { throw new illegalargumentexception("url == null"); } // 1.从url中获取wheelmaker名称 string wheelmakername = url.getparameter("wheel.maker"); if (wheelmakername == null) { throw new illegalargumentexception("wheelmakername == null"); } // 2.通过spi加载具体的wheelmaker wheelmaker wheelmaker = extensionloader.getextensionloader(wheelmaker.class).getextension(wheelmakername); // 3.调用目标方法 return wheelmaker.makewheel(url url); } } /** * 一个模拟的spi接口 */ @spi public interface carmaker { car makecar(url url); } /** * 汽车制造者spi接口的扩展类 */ public class racecarmaker implements carmaker { wheelmaker wheelmaker; //在injectextension方法中会通过setter注入adaptivewheelmaker //目前我们只知道自动装配行为的结果,原因会在“扩展点自动装配”小节分析 public setwheelmaker(wheelmaker wheelmaker) { this.wheelmaker = wheelmaker; } //实现的方法 public car makecar(url url) { //实际调用adaptivewheelmaker的makewheel方法,获得当前运行环境参数url下需要使用的wheel扩展类 wheel wheel = wheelmaker.makewheel(url); return new racecar(wheel, ...); } }
假设运行时传入这样一个url参数“dubbo://192.168.0.101:20880/xxxservice?wheel.maker=michelinwheelmaker”,那么racecar最终的wheel为扩展类“michelinwheelmaker”制造出来的轮胎。
4.2.获取自适应扩展类实例
/**************************************** 相关字段 ****************************************/ //缓存的自适应扩展类实例 private final holder<object> cachedadaptiveinstance = new holder<>(); //spi接口的扩展类中具有@adaptive注解的扩展类class缓存 private volatile class<?> cachedadaptiveclass = null; //创建自适应扩展类实例的异常信息 private volatile throwable createadaptiveinstanceerror; /**************************************** 相关方法 ****************************************/ /** * 获取自适应扩展类的实例 */ public t getadaptiveextension() { //从extensionloader的缓存字段中获取数据,cachedadaptiveinstance为一个holder<object>对象 object instance = cachedadaptiveinstance.get(); if (instance == null) { //需要判断一下创建自适应扩展对象的throwable缓存是否存在,如果存在,直接抛出 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("......"); } } } } else { throw new illegalstateexception("......"); } } return (t) instance; } /** * 创建自适应扩展类实例 */ private t createadaptiveextension() { try { //(1)调用getadaptiveextensionclass方法获取自适应扩展类的class; //(2)通过newinstance实例化一个自适应扩展类的对象; //(3)调用injectextension方法向自适应拓展类的实例中注入依赖,参考“扩展点自动装配”小节; return injectextension((t) getadaptiveextensionclass().newinstance()); } catch (exception e) { throw new illegalstateexception("......"); } } /** * 获取自适应扩展类的class */ private class<?> getadaptiveextensionclass() { //获取该extensionloader对应spi接口配置的所有扩展类(参考“getextensionclsses”小节) getextensionclasses(); //检查具有@adaptive注解的扩展类缓存,若缓存不为空,则直接返回缓存 if (cachedadaptiveclass != null) { return cachedadaptiveclass; } //如果spi接口配置的所有扩展类都没有被@adaptive标注,则创建自适应扩展类 return cachedadaptiveclass = createadaptiveextensionclass(); } /** * 创建自适应扩展类 */ private class<?> createadaptiveextensionclass() { //通过adaptiveclasscodegenerator的generate方法创建自适应扩展代码 //该方法会检测spi接口中是否有被@adapative注解的方法,对于要生成自适应扩展类的spi接口 //必须至少包含一个被@adaptive注解的方法,否则会抛出异常 string code = new adaptiveclasscodegenerator(type, cacheddefaultname).generate(); classloader classloader = findclassloader(); //获取编译器实现类,一样是通过adaptiveextension进行获取,获取之后进行编译 org.apache.dubbo.common.compiler.compiler compiler = extensionloader.getextensionloader(org.apache.dubbo.common.compiler.compiler.class).getadaptiveextension(); return compiler.compile(code, classloader); }
通过getadaptiveextension方法的流程可以发现,要想获得一个spi接口的自适应扩展类实例,有2种方式:
- 在spi接口的配置文件中配置具有@adaptive注解的扩展类,在执行解析spi接口配置文件方法getextensionclasses时,它会调用loadclass方法,该方法判断扩展类是否具有@adaptive注解,如果有,则将该类class缓存到extensionloader的字段“cachedadaptiveclass”中,然后直接实例化该class的实例并进行自动装配;
- 如果未配置@adaptive修饰的扩展类,则dubbo会使用字节码技术创建一个自适应扩展类,前提是spi接口上至少有一个被@adaptive注解的方法;
@documented @retention(retentionpolicy.runtime) @target({elementtype.type, elementtype.method}) public @interface adaptive { string[] value() default {}; }
可以看到,@adaptive注解既可以使用在类上,又可以使用在方法上。其包含一个字符串数组的属性,在通过字节码技术创建自适应扩展类时,该属性参与到生成逻辑中,具体的创建逻辑我们马上通过下一节来了解。
4.3.关于创建自适应扩展类
4.3.1.代码拼接
string code = new adaptiveclasscodegenerator(type, cacheddefaultname).generate();
首先传入spi接口的class与默认的扩展类名称(即@spi注解的value值)创建一个adaptiveclasscodegenerator实例,之后调用generate方法生成代码,adaptiveclasscodegenerator相对应的源码如下:
/**************************************** 相关字段 ****************************************/ //spi接口类型 private final class<?> type; //spi接口默认的扩展类名称,即@spi注解的value属性值 private string defaultextname; /**************************************** 相关方法 ****************************************/ /** * 可以看到,构造器并未做太多的事情,只是简单的将传入的参数为成员变量赋值 */ public adaptiveclasscodegenerator(class<?> type, string defaultextname) { this.type = type; this.defaultextname = defaultextname; } /** * 创建自适应扩展类的代码串 */ public string generate() { //遍历spi接口是否具有@adaptive注解修饰的方法,如果没有则抛出异常 if (!hasadaptivemethod()) { throw new illegalstateexception("......"); } //按照一个java类的代码组成顺序,拼接代码字符串 stringbuilder code = new stringbuilder(); //拼接包信息字符串: "package" + spi接口所在的包 code.append(generatepackageinfo()); //拼接import字符串: "import" + extensionloader的全限定名 code.append(generateimports()); //拼接类开头字符串: "public class" + spi接口简单名 + "$adaptive implements" + spi接口全限定名 + "{" //注意:使用全限定名的原因为import代码串中只导入extensionloader的类,下同 code.append(generateclassdeclaration()); //拼接每一个方法字符串,逻辑比较复杂,在generatemethod方法源码中详细说明 method[] methods = type.getmethods(); for (method method : methods) { code.append(generatemethod(method)); } //拼接类结束字符串: "}" code.append("}"); return code.tostring(); } /** * 检测该spi接口是否具有@adaptive修饰的方法 */ private boolean hasadaptivemethod() { return arrays.stream(type.getmethods()).anymatch(m -> m.isannotationpresent(adaptive.class)); } /** * 生成自适应扩展类的方法代码串 */ private string generatemethod(method method) { //获取方法返回值类型全限定名 string methodreturntype = method.getreturntype().getcanonicalname(); //获取方法名 string methodname = method.getname(); //获取方法内容,有无@adaptive修饰的方法其方法内容不同,详细见下generatemethodcontent源码 string methodcontent = generatemethodcontent(method); //获取方法参数列表,格式为"参数类型全限定名 arg0, 参数类型全限定名 arg1, ..." string methodargs = generatemethodarguments(method); //获取方法异常抛出,格式为"throws 异常1全限定名, 异常2全限定名, ..." string methodthrows = generatemethodthrows(method); //获取一个方法代码串 return string.format(code_method_declaration, methodreturntype, methodname, methodargs, methodthrows, methodcontent); } /** * 生成自适应扩展类的方法体代码串 */ private string generatemethodcontent(method method) { adaptive adaptiveannotation = method.getannotation(adaptive.class); stringbuilder code = new stringbuilder(512); //判断当前要生成的方法是否有@adaptive注解 if (adaptiveannotation == null) { //对于没有@adaptive注解的方法,生成"throw new unsupportedoperationexception(...)"代码 return generateunsupported(method); } else { //检查方法参数列表中是否有类型为"com.apache.dubbo.common.url"的参数 //简单提一下,com.apache.dubbo.common.url是dubbo框架中各组件的数据总线 int urltypeindex = geturltypeindex(method); if (urltypeindex != -1) { //如果方法参数列表中有url类型参数,则为该参数生成判断是否为null以及赋值的代码: //(generateurlnullcheck方法比较简单,不进行详细的源码分析,这里只给出逻辑) //if (arg%d == null) throw new illegalargumentexception("url == null"); //com.apache.dubbo.common.url url = arg%d; //d的值为urltypeindex code.append(generateurlnullcheck(urltypeindex)); } else { //如果方法参数列表中没有url类型参数,则需要遍历参数列表中每一个参数的类型信息, //判断哪一个参数具有"public url getxxx()"签名形式的方法,如果有则停止遍历且生成如下代码: //(generateurlassignmentindirectly方法比较简单,不进行详细的源码分析,这里只给出逻辑) //if (arg%d == null) 备注:此处的d为具备"public url getxxx()"方法的参数下标,从0开始 // throw new illegalargumentexception("参数全限定名 + argument == null"); //if (arg%d.getter方法名() == null) // throw new illegalargumentexception(参数全限定名 + argument geturl() == null); //com.apache.dubbo.common.url url = arg%d.getter方法名(); code.append(generateurlassignmentindirectly(method)); } //获取该方法的@adaptive注解的属性值value(为一个string数组),这里列出处理逻辑 //如果属性值value为非空数组,直接获取数组内容即可; //如果value为空数组,则需将spi接口的类名按照驼峰命名法进行检测,对每个驼峰进行分割并插入"."号, //然后转为小写,比如loadbalance经过处理后,得到load.balance string[] value = getmethodadaptivevalue(adaptiveannotation); //判断当前方法的参数列表中是否有类型为org.apache.dubbo.rpc.invocation的参数 boolean hasinvocation = hasinvocationargument(method); //为当前方法参数列表中第一个类型为org.apache.dubbo.rpc.invocation的参数生成判null语句以及调用语句 //if (arg%d == null) throw new illegalargumentexception("invocation == null"); //string methodname = arg%d.getmethodname(); //%d是org.apache.dubbo.rpc.invocation类型的参数在参数列表中的下标 code.append(generateinvocationargumentnullcheck(method)); //使用前面获取到的字符串数组value以及invocation参数存在标识拼接获取扩展类extname的代码串, //这是自适应扩展类核心的代码,因为自适应扩展类的目的就是要根据当前运行参数, //判断应该获取spi接口的哪一个扩展类,而extensionloader.getextension方法的参数就是这个extname //该方法逻辑比较复杂,判断分支较多,详细的分析在下面generateextnameassignment中 code.append(generateextnameassignment(value, hasinvocation)); //对上一步获取的局部变量extname拼接其判null代码 //if(extname == null) throw new illegalstateexception("failed to get extension name from..."); code.append(generateextnamenullcheck(value)); //生成获取extname对应扩展类实例的代码串,如下: //%s extension = (%<s)extensionloader.getextensionloader(%s.class).getextension(extname); //其中%s为成员变量type.getname,即spi接口的class的全限定名 code.append(generateextensionassignment()); //生成目标方法调用逻辑,被@adaptive注解的方法,第一个任务是根据运行时参数获取对应的扩展类实例, //第二个任务就是调用这个实例的同名方法。生成的方法调用代码串格式为: //(1)如果该方法无返回值"extension.方法名(arg0, arg2, ..., argn);" //(2)如果该方法有返回值"return extension.方法名(arg0, arg1, ..., argn);" //其中extension为上一步生成的扩展类实例变量名,arg0、arg1就为当前@adaptive注解方法的参数名 code.append(generatereturnandinvocation(method)); } return code.tostring(); } /** * 扩展名extname获取代码串 */ private string generateextnameassignment(string[] value, boolean hasinvocation) { string getnamecode = null; //反向遍历value,目的是生成从url中获取拓展名的代码,生成的代码会赋值给getnamecode变量 for (int i = value.length - 1; i >= 0; --i) { //当遍历的元素是最后一个元素时 if (i == value.length - 1) { //若默认扩展名不空(即@spi注解的value值不空) if (null != defaultextname) { //由于protocol是url的成员变量,可通过getprotocol方法获取,其他的则是从 //url的成员变量parameters(一个map<string, string>)中获取。 //因为获取方式不同,所以这里要判断value[i]是否为protocol if (!"protocol".equals(value[i])) { //需要判断一下hasinvocation标识(即当前方法是否有invocation参数) if (hasinvocation) { //生成的代码功能等价于下面的代码: //url.getmethodparameter(methodname, value[i], defaultextname) //注意,methodname是generateinvocationargumentnullcheck生成的局部变量,下同 getnamecode = string.format("url.getmethodparameter(methodname, \"%s\", \"%s\")", value[i], defaultextname); } else { //生成的代码功能等价于下面的代码: //url.getparameter(value[i], defaultextname) getnamecode = string.format("url.getparameter(\"%s\", \"%s\")", value[i], defaultextname); } } else { //生成的代码功能等价于下面代码: //( url.getprotocol() == null ? defaultextname : url.getprotocol() ) getnamecode = string.format("( url.getprotocol() == null ? \"%s\" : url.getprotocol() )", defaultextname); } //若默认扩展名为空 } else { if (!"protocol".equals(value[i])) { if (hasinvocation) { //生成的代码格式同上,即 //url.getmethodparameter(methodname, value[i], defaultextname) getnamecode = string.format("url.getmethodparameter(methodname, \"%s\", \"%s\")", value[i], defaultextname); } else { //生成的代码功能等价于:url.getparameter(value[i]) getnamecode = string.format("url.getparameter(\"%s\")", value[i]); } } else { //生成的代码功能等价于:url.getprotocol() getnamecode = "url.getprotocol()"; } } //当遍历的元素不为最后一个时 } else { if (!"protocol".equals(value[i])) { if (hasinvocation) { //生成的代码同上,即: //url.getmethodparameter(methodname, value[i], defaultextname) getnamecode = string.format("url.getmethodparameter(methodname, \"%s\", \"%s\")", value[i], defaultextname); } else { //在上一次获取的getnamecode代码结果基础上,再次获取getnamecode,即一层层的获取值 //生成的代码功能等价于下面的代码: //url.getparameter(value[i], getnamecode) //以transporter接口的connect方法为例,最终生成的代码如下: //url.getparameter("client", url.getparameter("transporter", "netty")) getnamecode = string.format("url.getparameter(\"%s\", %s)", value[i], getnamecode); } } else { //在上一次获取的getnamecode代码结果基础上,再次获取getnamecode,即一层层的获取值 //生成的代码功能等价于下面的代码: //url.getprotocol() == null ? getnamecode : url.getprotocol() //以protocol接口的connect方法为例,最终生成的代码如下: //url.getprotocol() == null ? "dubbo" : url.getprotocol() getnamecode = string.format("url.getprotocol() == null ? (%s) : url.getprotocol()", getnamecode); } } } //返回生成extname的代码:"string extname = getnamecode;" return string.format(code_ext_name_assignment, getnamecode); }
4.3.2.代码编译
classloader classloader = findclassloader(); //获取编译器实现类,一样是通过adaptiveextension进行获取,获取之后进行编译 //在这里具体获取compiler的细节略去,最终获取到javassistcompiler类的实例进行编译 org.apache.dubbo.common.compiler.compiler compiler = extensionloader.getextensionloader(org.apache.dubbo.common.compiler.compiler.class).getadaptiveextension(); return compiler.compile(code, classloader);
对于这段代码,我们可以运用本小节学到知识,来分析一下compiler接口的自适应扩展类是什么。
adaptive=org.apache.dubbo.common.compiler.support.adaptivecompiler jdk=org.apache.dubbo.common.compiler.support.jdkcompiler javassist=org.apache.dubbo.common.compiler.support.javassistcompiler
一共配置了3个扩展类,根据name的名称,可以肯定adaptivecompiler是具有@adaptive注解的扩展类
@adaptive public class adaptivecompiler implements compiler { private static volatile string default_compiler; 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); } }
根据4.2小节中的代码逻辑,在具有@adaptive注解修饰的扩展类的前提下,自适应扩展类实例一定获取到这个被修饰的类实例,因此“extensionloader.getextensionloader(....compiler.class).getadaptiveextension();”这段代码获取到了一个adaptivecompiler的实例。adaptivecompiler的compile方法很简单,由于成员变量“default_compiler”始终为null,其会调用extensionloader的getdefaultextension方法获取默认的扩展类实例,即@spi接口注解value值作为name的实例,看看compiler接口代码:
@spi("javassist") public interface compiler { class<?> compile(string code, classloader classloader); }
其默认的扩展类的name为“javassist”,即类“org.apache.dubbo.common.compiler.support.javassistcompiler”,这个类的具体compile方法不多赘述,就是校验代码字符串格式的正确性,并进行加载。
五、扩展点自动装配
/** * 自动装配扩展类实例 */ private t injectextension(t instance) { try { //如果objectfactory不为空,则进行自动装配 if (objectfactory != null) { //遍历扩展类实例的所有方法 for (method method : instance.getclass().getmethods()) { //检测方法是否以set开头、只有一个参数、访问修饰符为public if (issetter(method)) { //对于有@disableinject的注解的setter方法,不需要注入 if (method.getannotation(disableinject.class) != null) { continue; } //获取setter方法的参数类型 class<?> pt = method.getparametertypes()[0]; //判断参数类型是否是原始类型(基本类型+string+基本类型的包装类+date) if (reflectutils.isprimitives(pt)) { continue; } try { //获取要注入属性名,比如setname方法中对应的属性名为name string property = getsetterproperty(method); //从objectfactory中根据属性名与属性的class类型获取依赖对象, //获取到的是一个spi接口的自适应扩展类的对象或者spring环境下的一个bean, //objectfactory.getextension方法的细节我们在extensionfactory中将详细讨论 object object = objectfactory.getextension(pt, property); if (object != null) { //调用setter方法进行注入 method.invoke(instance, object); } } catch (exception e) { logger.error("failed to inject via method ..."); } } } } } catch (exception e) { logger.error(e.getmessage(), e); } return instance; }
private extensionloader(class<?> type) { this.type = type; objectfactory = (type == extensionfactory.class ? null : extensionloader.getextensionloader(extensionfactory.class).getadaptiveextension()); }
这几行简单的代码包含了很多信息:首先,extensionfactory自身也是一个spi接口,其同样能够通过extensionloader进行初始化。其次,当获取一个spi接口的extensionloader时,如果该spi接口为extensionfactory,则不会设置objectfactory字段值,否则会通过getadaptiveextension方法拿到一个extensionfactory的实例并将字段objectfactory的值设置为它。
5.1.extensionfactory
@spi public interface extensionfactory { <t> t getextension(class<t> type, string name); }
extensionfactory这个接口的继承树如下图所示:
它有3个实现类,分别是adaptiveextensionfactory、spiextensionfactory、springextensionfactory,相关的meta-info配置文件内容如下:
#位于dubbo-common模块下的meta-info/dubbo/internal/com.apache.dubbo.common.extensionfactory文件 adaptive=org.apache.dubbo.common.extension.factory.adaptiveextensionfactory spi=org.apache.dubbo.common.extension.factory.spiextensionfactory #位于dubbo-spring模块下的meta-inf/dubbo/internal/com.apache.dubbo.common.extensionfactory文件 spring=org.apache.dubbo.config.spring.extension.springextensionfactory
5.2.adaptiveextensionfactory
@adaptive public class adaptiveextensionfactory implements extensionfactory { //维护了一组extensionfctory接口扩展类的实例 private final list<extensionfactory> factories; //构造方法,获取所有extensionfactory配置的扩展类实例 public adaptiveextensionfactory() { //加载extensionfactory对应的extensionloader extensionloader<extensionfactory> loader = extensionloader.getextensionloader(extensionfactory.class); list<extensionfactory> list = new arraylist<extensionfactory>();、 //getsupportedextensions方法用于获取extensionloader的cachedclasses缓存的keyset //即spi接口配置文件中name的set集合 for (string name : loader.getsupportedextensions()) { //根据name名字,调用getextension方法获取对应扩展类的实例并缓存 list.add(loader.getextension(name)); } factories = collections.unmodifiablelist(list); } @override public <t> t getextension(class<t> type, string name) { for (extensionfactory factory : factories) { //调用每一个extensionfactory实现类的getextension方法,并返回第一个不为null的对象 t extension = factory.getextension(type, name); if (extension != null) { return extension; } } return null; } }
5.3.spiextensionfactory
public class spiextensionfactory implements extensionfactory { @override public <t> t getextension(class<t> type, string name) { if (type.isinterface() && type.isannotationpresent(spi.class)) { extensionloader<t> loader = extensionloader.getextensionloader(type); //getsupportedextensions方法用于获取extensionloader的cachedclasses缓存的keyset //即spi接口配置文件中name的set集合 if (!loader.getsupportedextensions().isempty()) { return loader.getadaptiveextension(); } } return null; } }
5.4.springextensionfactory
public class springextensionfactory implements extensionfactory { private static final logger logger = loggerfactory.getlogger(springextensionfactory.class); private static final set<applicationcontext> contexts = new concurrenthashset<applicationcontext>(); private static final applicationlistener shutdown_hook_listener = new shutdownhooklistener(); public static void addapplicationcontext(applicationcontext context) { contexts.add(context); if (context instanceof configurableapplicationcontext) { ((configurableapplicationcontext) context).registershutdownhook(); dubboshutdownhook.getdubboshutdownhook().unregister(); } //先springcontext注册dubbo关闭钩子 beanfactoryutils.addapplicationlistener(context, shutdown_hook_listener); } //省略了一些contexts的crud方法... @override @suppresswarnings("unchecked") public <t> t getextension(class<t> type, string name) { //不支持被@spi注解标注的接口类型 if (type.isinterface() && type.isannotationpresent(spi.class)) { return null; } //首先根据name从spring上下文获取bean,并验证该bean与type是否一致 for (applicationcontext context : contexts) { if (context.containsbean(name)) { object bean = context.getbean(name); if (type.isinstance(bean)) { return (t) bean; } } } logger.warn("no spring extension (bean) named ..."); //如果type的类型为object,直接返回null if (object.class == type) { return null; } //尝试根据type从spring上下文获取bean,如果type对应的bean并非唯一,直接报错 for (applicationcontext context : contexts) { try { return context.getbean(type); } catch (nouniquebeandefinitionexception multibeanexe) { logger.warn("find more than 1 spring extensions (beans) of type ..."); } catch (nosuchbeandefinitionexception nobeanexe) { if (logger.isdebugenabled()) { logger.debug("error when get spring extension(bean) for type: ..."); } } } logger.warn("no spring extension (bean) named: ..."); //未找到,返回null return null; } private static class shutdownhooklistener implements applicationlistener { @override public void onapplicationevent(applicationevent event) { if (event instanceof contextclosedevent) { dubboshutdownhook shutdownhook = dubboshutdownhook.getdubboshutdownhook(); shutdownhook.dodestroy(); } } } }
springextensionfactory维护了spring上下文集合“set<applicationcontext>”。在getextension方法中,通过spring上下文去获取实例。并且,springextensionfactory在设置springcontext时,会向获取到的context注册一个spring容器关闭事件的监听钩子,用于关闭dubbo。
六、扩展点自动包装
package com.alibaba.xxx; import org.apache.dubbo.rpc.protocol; public class xxxprotocolwrapper implements protocol { protocol impl; //单参数构造函数,且参数类型为其实现的spi接口类型protocol public xxxprotocolwrapper(protocol protocol) { impl = protocol; } // 接口方法做一个操作后,再调用extension的方法 public void refer() { //... 一些操作 impl.refer(); // ... 一些操作 } }
自动包装的机制能够近似的实现aop的功能,通过wrapper类可以把所有扩展点公共逻辑移至wrapper中,新加的wrapper在所有的扩展点上添加了逻辑。
七、扩展点自动激活