5.2 dubbo-compiler源码解析
Posted 赵计刚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5.2 dubbo-compiler源码解析相关的知识,希望对你有一定的参考价值。
1 ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class); 2 final Protocol dubboProtocol = loader.getExtension("dubbo"); 3 final Protocol adaptiveExtension = loader.getAdaptiveExtension();
在2.2 dubbo-spi源码解析讲了第一句,在第四章 dubbo内核之aop源码解析讲了第二句,本章来讲最后一句。
getAdaptiveExtension()层级结构:
1 ExtensionLoader<T>.getAdaptiveExtension() 2 --createAdaptiveExtension() 3 ----injectExtension(getAdaptiveExtensionClass()) 4 ------getAdaptiveExtensionClass() 5 --------getExtensionClasses()//从spi文件中查找实现类上具有@Adaptive注解的类 6 ----------loadExtensionClasses() 7 ------------loadFile(Map<String, Class<?>> extensionClasses, String dir) 8 --------createAdaptiveExtensionClass()//如果从spi文件中没有找到实现类上具有@Adaptive注解的类,则动态创建类
这里最后执行到了createAdaptiveExtensionClass()方法。
1 private Class<?> createAdaptiveExtensionClass() { 2 String code = createAdaptiveExtensionClassCode(); 3 ClassLoader classLoader = findClassLoader(); 4 com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); 5 return compiler.compile(code, classLoader); 6 }
一 构造代码串
createAdaptiveExtensionClassCode()方法中会判断如果一个类中没有@Adaptive注解的方法,则直接抛出IllegalStateException异常;否则,会为有@Adaptive注解的方法构造代码,而没有@Adaptive注解的方法直接抛出UnsupportedOperationException异常。
构造出的结果为:
1 package com.alibaba.dubbo.rpc; 2 3 import com.alibaba.dubbo.common.extension.ExtensionLoader; 4 5 public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol { 6 public void destroy() { 7 throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); 8 } 9 public int getDefaultPort() { 10 throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); 11 } 12 public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException { 13 if (arg1 == null) 14 throw new IllegalArgumentException("url == null"); 15 com.alibaba.dubbo.common.URL url = arg1; 16 String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); 17 if(extName == null) 18 throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); 19 com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); 20 return extension.refer(arg0, arg1); 21 } 22 public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException { 23 if (arg0 == null) 24 throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); 25 if (arg0.getUrl() == null) 26 throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null"); 27 com.alibaba.dubbo.common.URL url = arg0.getUrl(); 28 String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); 29 if(extName == null) 30 throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); 31 com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); 32 return extension.export(arg0); 33 } 34 }
说明:
- 该生成类在dubbo2.5.3中export和refer方法声明处的异常抛出是错的(在dubbo2.5.4改正了);
- 类名在dubbo2.5.4之前(包含2.5.4)也是错的Protocol$Adpative,dubbo2.5.5改正了。
二 获取Compiler装饰类
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
先看一下com.alibaba.dubbo.common.compiler.Compiler接口:
1 @SPI("javassist") 2 public interface Compiler { 3 Class<?> compile(String code, ClassLoader classLoader); 4 }
@SPI的默认值为javassist,根据上一节的经验,默认获取的Compiler接口的实现类将是META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件中的key为javassit的实现类。文件内容如下:
1 adaptive=com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler 2 jdk=com.alibaba.dubbo.common.compiler.support.JdkCompiler 3 javassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler
根据上一节对ExtensionFactory的getAdaptiveExtension()的讲解,我们最终获取到的Compiler的AdaptiveExtension将是com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler。
来看源码,首先是获取ExtensionLoader<com.alibaba.dubbo.common.compiler.Compiler> loader,最终的loader包含如下属性:
- Class<?> type = interface com.alibaba.dubbo.common.compiler.Compiler
- ExtensionFactory objectFactory = AdaptiveExtensionFactory(适配类)
- factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]
之后,是loader.getAdaptiveExtension()。
在该方法中,首先会调用createAdaptiveExtension()创建实例,之后放入缓存,然后返回。
1 private T createAdaptiveExtension() { 2 try { 3 return injectExtension((T) getAdaptiveExtensionClass().newInstance()); 4 } catch (Exception e) { 5 throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), 6 e); 7 } 8 } 9 10 private Class<?> getAdaptiveExtensionClass() { 11 /** 12 * 获取ExtensionClasses和适配类 13 * 其中适配类cachedAdaptiveClass如果不存在,则需要使用createAdaptiveExtensionClass()进行创建. 14 */ 15 getExtensionClasses(); 16 if (cachedAdaptiveClass != null) { 17 return cachedAdaptiveClass; 18 } 19 return cachedAdaptiveClass = createAdaptiveExtensionClass(); 20 }
在createAdaptiveExtension()中首先会调用getAdaptiveExtensionClass()获取ExtensionClasses和修饰类,之后将修饰类返回。根据META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件的内容,最后返回
- ExtensionClasses
- "jdk" -> "class com.alibaba.dubbo.common.compiler.support.JdkCompiler"
- "javassist" -> "class com.alibaba.dubbo.common.compiler.support.JavassistCompiler"
- cachedAdaptiveClass=class com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler
之后调用AdaptiveCompiler的无参构造器创建AdaptiveCompiler对象实例,然后执行injectExtension(T instance)(这里没起作用)为AdaptiveCompiler对象实例注入相应的属性(AdaptiveCompiler必须提供相应的setter方法),最后返回AdaptiveCompiler对象实例。
三 编译代码并加载为Class<?>对象
创建好AdaptiveCompiler对象实例之后,然后执行下面的方法。
Class<?> compile(String code, ClassLoader classLoader)
看一下AdaptiveCompiler全部源码:
1 @Adaptive 2 public class AdaptiveCompiler implements Compiler { 3 private static volatile String DEFAULT_COMPILER;//默认的编译器的名字 4 5 public static void setDefaultCompiler(String compiler) { 6 DEFAULT_COMPILER = compiler; 7 } 8 9 /** 10 * 典型的动态代理,在代理类中,存放着真实对象,使用真实对象执行相应的方法 11 */ 12 public Class<?> compile(String code, ClassLoader classLoader) { 13 Compiler compiler; 14 ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class); 15 String name = DEFAULT_COMPILER; // copy reference 16 if (name != null && name.length() > 0) { 17 compiler = loader.getExtension(name);//获取名字为name的实现类的实例,在获取的过程中会完成IOC和AOP 18 } else { 19 compiler = loader.getDefaultExtension();//获取默认的JavassitCompiler,调用getExtension(cachedDefaultName) 20 } 21 return compiler.compile(code, classLoader);//根据获取到的实现类compiler实例,来执行真正的动态生成类的代码 22 } 23 }
这里执行的是compiler = loader.getDefaultExtension(),该方法不说了,就是调用了getExtension(cachedDefaultName)生成一个JavassistCompiler的实例。之后就是执行JavassistCompiler的compile(String code, ClassLoader classLoader)方法。
1 package com.alibaba.dubbo.common.compiler.support; 2 3 import com.alibaba.dubbo.common.compiler.Compiler; 4 import com.alibaba.dubbo.common.utils.ClassHelper; 5 6 import java.util.regex.Matcher; 7 import java.util.regex.Pattern; 8 9 /** 10 * Abstract compiler. (SPI, Prototype, ThreadSafe) 11 */ 12 public abstract class AbstractCompiler implements Compiler { 13 private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\\\s+([$_a-zA-Z][$_a-zA-Z0-9\\\\.]*);"); 14 private static final Pattern CLASS_PATTERN = Pattern.compile("class\\\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\\\s+"); 15 16 /** 17 * 1 根据正则表达式从code中获取包名和类名,组成全类名 18 * 2 根据全类名使用Class.forName创建Class<?>,如果该类在jvm中存在,则成功,否则抛出ClassNotFoundException, 19 * 执行doCompile方法。 20 */ 21 public Class<?> compile(String code, ClassLoader classLoader) { 22 code = code.trim(); 23 Matcher matcher = PACKAGE_PATTERN.matcher(code); 24 String pkg; 25 if (matcher.find()) { 26 pkg = matcher.group(1); 27 } else { 28 pkg = ""; 29 } 30 matcher = CLASS_PATTERN.matcher(code); 31 String cls; 32 if (matcher.find()) { 33 cls = matcher.group(1); 34 } else { 35 throw new IllegalArgumentException("No such class name in " + code); 36 } 37 String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls; 38 try { 39 return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass())); 40 } catch (ClassNotFoundException e) { 41 if (!code.endsWith("}")) { 42 throw new IllegalStateException("The java code not endsWith \\"}\\", code: \\n" + code + "\\n"); 43 } 44 try { 45 return doCompile(className, code); 46 } catch (RuntimeException t) { 47 throw t; 48 } catch (Throwable t) { 49 throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \\n" + code + "\\n, stack: " + ClassUtils.toString(t)); 50 } 51 } 52 } 53 54 protected abstract Class<?> doCompile(String name, String source) throws Throwable; 55 }
该方法会执行JavassistCompiler的Class<?> doCompile(String name, String source)方法了,在该方法中,使用正则表达式对传入的源码解析成属性方法等,并使用javassist的API创建Class<?>。
最后,该final Protocol adaptiveExtension = loader.getAdaptiveExtension();代码返回的adaptiveExtension = Protocol$Adaptive实例。
总结(再啰嗦一遍):
- ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()最终返回的是:AdaptiveExtensionFactory实例,其属性factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]
- 不管是获取哪一个SPI接口(除了ExtensionFactory.接口)的ExtensionLoader,最终一定会有一个objectFactory=上述的AdaptiveExtensionFactory实例
- getAdaptiveExtension():作用就是获取一个装饰类或动态代理类的实例, 如果有@Adaptive注解的类,则直接返回该类的实例,否则返回一个动态代理类的实例(例如Protocol$Adaptive的实例),之后完成属性注入(dubbo-IOC),最后返回实例。
- getExtension(String key):作用就是从extensionClasses(即指定SPI接口的没有@Adaptive的实现类)获取指定key的extensionClass,并且实例化,之后完成属性注入(dubbo-IOC),再之后完成dubbo-AOP,最后返回实例。
以上是关于5.2 dubbo-compiler源码解析的主要内容,如果未能解决你的问题,请参考以下文章