Dubbo为了实现基于spi思想的扩展特性,特别是能够灵活添加额外功能,要能够动态生成一个叫做控制或适配并实现扩展或策略选择功能的类。当然对应已知需求如Protocol, ProxyFactory他们的策略选择的适配类代码dubbo直接提供也无妨,但是dubbo作为一个高扩展性的框架,使得用户能够添加自己的需求,根据配置动态生成自己的适配类代码,这样就需要在运行的时候去编译加载这个适配类的代码。
动态编译实现的类图:
编译接口定义
@SPI("javassist")
public interface Compiler {
Class> compile(String code, ClassLoaderclassLoader);
}
SPI注解表示如果没有配置,dubbo默认选用javassist编译源代码
接口方法compile第一个入参code,就是java的源代码
接口方法compile第二个入参classLoader,按理是类加载器用来加载编译后的字节码,其实没用到,都是根据当前线程或者调用方的classLoader加载的
SPI机制,(在java.util.ServiceLoader里有比较详细的介绍)简单来说就是为某个接口寻找服务实现的机制,实现方式可参看spi约定。
从接口定义代码我们可以看到dubbo使用了Javasist实现了SPI,接下来我们看看Javasist是怎么实现SPI的。
JavaSist
使用javasist生成字节码示例如下:
public static void main(String[] args)throws Exception{
ClassPool pool = ClassPool.getDefault();
//创建Programmer类
CtClass cc= pool.makeClass("com.mining.producer");
//定义code方法
CtMethod method = CtNewMethod.make("public void code(){}", cc);
//插入方法代码
method.insertBefore("System.out.println("I'm a Programmer,Just Coding.....");");
cc.addMethod(method);
//保存生成的字节码
cc.writeFile("d://temp");
}
运行代码后生成字节码类:
Dubbo中使用Javasist框架生成代理
JavassistProxyFactory:利用字节码技术来创建对象。
看似跟jdk生成代理一样, 其实这里的Proxy类不是jdk中自带那个生成代理对象的类是:com.alibaba.dubbo.common.bytecode.Proxy。
这个dubbo自己写的Proxy类,利用要代理的接口利用javassist工具生成代理代码。
获取Invoker 对象
根据传入的 proxy对象的类信息创建对它的包装对象Wrapper
返回Invoker对象实例, 这个invoker对象invoke方法可以根据传入的invocation对象中包含的方法名,方法参数来调用proxy对象返回调用结果
com.alibaba.dubbo.common.bytecode.Proxy 生成代理对象的工具类
1.遍历所有入参接口,以;分割连接起来, 以它为key以map为缓存查找如果有,说明代理对象已创建返回
2.利用AtomicLong对象自增获取一个long数组来作为生产类的后缀,防止冲突
3.遍历接口获取所有定义的方法,加入到一个集合Set
获取方法y应该在methods数组中的索引下标ix
获取方法的参数类型以及返回类型
构建方法体return ret= handler.invoke(this, methods[ix], args);
这里的方法调用其实是委托给InvokerInvocationHandler实例对象的,去调用真正的实例方法加入到methods数组中
4.创建代理实例对象ProxyInstance
类名为 pkg + “.poxy”+id = 包名 + “.poxy” +自增数值
添加静态字段Method[] methods;
添加实例对象InvokerInvocationHandler hanler
添加构造器参数是InvokerInvocationHandler
添加无参构造器
利用工具类ClassGenerator生成对应的字节码
5. 创建代理对象,它的newInstance(handler)方法用来创建基于我们接口的代理
代理对象名Proxy + id
继承于Proxy, 所以要实现newInstance方法
添加默认构造器
实现方法newInstance代码, new pcn(hadler) 这里pcn就是前面生成的代理对象类名
利用工具类ClassGenerator生成字节码并实例化对象返回
閱讀更多 HelloWorld應用 的文章