博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dubbo使用javassist生成动态类
阅读量:6540 次
发布时间:2019-06-24

本文共 7350 字,大约阅读时间需要 24 分钟。

Dubbo使用javassist生成动态类

在服务(本地和远程)暴露的时候会调用proxyFactory.getInvoker方法

具体位置:

  • 本地暴露:ServiceConfig#exportLocal line:538
  • 远程暴露: ServiceConfig#doExportUrlsFor1Protocol line:512

会先调用AOP织入的类StubProxyFactoryWrapper#getInvoker

然后执行JavassistProxyFactory#getInvoker

JavassistProxyFactory#getInvoker如下

public 
Invoker
getInvoker(T proxy, Class
type, URL url) { // getWrapper会生成代理类 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker
(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class
[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } };}

然后进入Wrapper#getWrapper--> Wrapper#makeWrapper, 具体代码就在这个makeWrapper方法里面

例如现在暴露的服务如下:

public interface TestService {    String getData(String var1);    List
getList();}

那么生成的代理类如下:

public class Wrapper0 extends com.alibaba.dubbo.common.bytecode.Wrapper {    /**     * 属性名, 属性类型     */    public static java.util.Map pts = new HashMap
>(); public static String[] pns = new String[0]; /** * 所有的方法名 */ public static String[] mns = {"getData"}; /** * 本类中的所有方法名 */ public static String[] dmns = {"getData"}; /** * 一个方法中所有的参数类型 mts[n]属性的个数和方法的个数形同 */ public static Class[] mts0 = {String.class}; public static Class[] mts1 = {List.class}; @Override public String[] getPropertyNames() { return pns; } @Override public boolean hasProperty(String n) { return pts.containsKey(n); } @Override public Class getPropertyType(String n) { return (Class) pts.get(n); } @Override public String[] getMethodNames() { return mns; } @Override public String[] getDeclaredMethodNames() { return dmns; } @Override public void setPropertyValue(Object o, String n, Object v) { per.qiao.service.TestService w; try { w = ((per.qiao.service.TestService) o); } catch (Throwable e) { throw new IllegalArgumentException(e); } throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService."); } @Override public Object getPropertyValue(Object o, String n) { per.qiao.service.TestService w; try { w = ((per.qiao.service.TestService) o); } catch (Throwable e) { throw new IllegalArgumentException(e); } if (n.equals("list")) { return w.getList(); } throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService."); } /** * 在调用接口时,就时调用的这个方法 @param o 接口实例 @param n 方法名 @param p 参数类型 @param v 参数 */ @Override public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException { per.qiao.service.TestService w; try { w = ((per.qiao.service.TestService) o); } catch (Throwable e) { throw new IllegalArgumentException(e); } try { //这个try范围内就是你所需要暴露的所有方法 if ("getData".equals(n) && p.length == 1) { return w.getData((java.lang.String) v[0]); } if ("getList".equals(n) && p.length == 0) { return w.getList(); } } catch (Throwable e) { throw new java.lang.reflect.InvocationTargetException(e); } throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + n + "\" in class per.qiao.service.TestService."); }}

javassist生成动态代理类的示例

public class CompilerByJavassist {    public static void main(String[] args) throws Exception {        // ClassPool:CtClass对象的容器        ClassPool pool = ClassPool.getDefault();        // 通过ClassPool生成一个public新类Emp.java        CtClass ctClass = pool.makeClass("per.qiao.javassist.Qiao");        // 添加属性 private String name        CtField nameFild = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);        nameFild.setModifiers(Modifier.PRIVATE);        ctClass.addField(nameFild);        // 其次添加熟悉privtae int age        CtField ageField = new CtField(pool.getCtClass("int"), "age", ctClass);        ageField.setModifiers(Modifier.PRIVATE);        ctClass.addField(ageField);        // 为属性name和age添加getXXX和setXXX方法        ctClass.addMethod(CtNewMethod.getter("getName", nameFild));        ctClass.addMethod(CtNewMethod.setter("setName", nameFild));        ctClass.addMethod(CtNewMethod.getter("getAge", ageField));        ctClass.addMethod(CtNewMethod.setter("setAge", ageField));        // 添加构造函数        CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);        // 为构造函数设置函数体        StringBuffer buffer = new StringBuffer();        buffer.append("{\n").append("name=\"qiaogege\";\n").append("age=25;\n}");        ctConstructor.setBody(buffer.toString());        // 把构造函数添加到新的类中        ctClass.addConstructor(ctConstructor);        // 添加自定义方法  public void printInfo {...}        CtMethod ctMethod = new CtMethod(CtClass.voidType, "printInfo", new CtClass[] {}, ctClass);        // 为自定义方法设置修饰符        ctMethod.setModifiers(Modifier.PUBLIC);        // 为自定义方法设置函数体        StringBuffer buffer2 = new StringBuffer();        buffer2.append("{\nSystem.out.println(\"begin!\");\n")                .append("System.out.println(name);\n")                .append("System.out.println(age);\n")                .append("System.out.println(\"over!\");\n").append("}");        ctMethod.setBody(buffer2.toString());        ctClass.addMethod(ctMethod);        //最好生成一个class        Class
clazz = ctClass.toClass(); Object obj = clazz.newInstance(); //ctClass.debugWriteFile("E://Qiao.class"); //反射 执行方法 obj.getClass().getMethod("printInfo", new Class[] {}) .invoke(obj, new Object[] {}); ctClass.debugWriteFile("E://Emp.class"); // 把生成的class文件写入文件 byte[] byteArr = ctClass.toBytecode(); FileOutputStream fos = new FileOutputStream(new File("E://Qiao.class")); fos.write(byteArr); fos.close(); }}

生成的Class文件放入IDEA中反编译后的结果如下

public class Qiao {    private String name = "qiaogege";    private int age = 25;    public String getName() {        return this.name;    }    public void setName(String var1) {        this.name = var1;    }    public int getAge() {        return this.age;    }    public void setAge(int var1) {        this.age = var1;    }    public Qiao() {    }    public void printInfo() {        System.out.println("begin!");        System.out.println(this.name);        System.out.println(this.age);        System.out.println("over!");    }}

小结:

1. Dubbo通过javassist动态生成一个代理类对象,该对象不同于普通的javassist生成的对象,而是只记录了暴露接口中的方法的相关参数,生成一个Wrapper类型的对象,并保存在WRAPPER_MAP中,通过invokeMethod方法来执行相应的方法2. 再将生成的Wrapper对象包装在AbstractProxyInvoker中进行服务暴露

转载于:https://www.cnblogs.com/qiaozhuangshi/p/11007024.html

你可能感兴趣的文章
为什么有人讨厌 Google 的新 Logo?
查看>>
腾讯2017暑期实习编程题3
查看>>
Intellij IDEA 构建Spring Web项目 — 用户登录功能
查看>>
[AHOI2013]作业
查看>>
git push被忽略的文件 处理
查看>>
C#中用ILMerge将所有引用的DLL打成一个DLL文件
查看>>
PHP生成HTML静态页面
查看>>
Makefile 中:= ?= += =的区别【转】
查看>>
使用makecontext实现用户线程【转】
查看>>
Comet:基于 HTTP 长连接的“服务器推”技术
查看>>
BZOJ 2733: [HNOI2012]永无乡 启发式合并treap
查看>>
四种方法校验数组中是否包含某个指定的字符串
查看>>
29、Java并发性和多线程-非阻塞算法
查看>>
安装OpenResty开发环境
查看>>
第0课 从0开始
查看>>
hadoop无法启动DataNode问题
查看>>
java泛型中<?>和<T>区别
查看>>
这里是指推送通知跟NSNotification有区别:
查看>>
用户ID的代码生成
查看>>
win7经常出现“关闭xxxx前您必须关闭所有会话框”
查看>>