Dubbo使用javassist生成动态类
Posted qiaozhuangshi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo使用javassist生成动态类相关的知识,希望对你有一定的参考价值。
Dubbo使用javassist生成动态类
在服务(本地和远程)暴露的时候会调用proxyFactory.getInvoker方法
具体位置:
- 本地暴露:ServiceConfig#exportLocal line:538
- 远程暴露: ServiceConfig#doExportUrlsFor1Protocol line:512
会先调用AOP织入的类StubProxyFactoryWrapper#getInvoker
然后执行JavassistProxyFactory#getInvoker
JavassistProxyFactory#getInvoker如下
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url)
// getWrapper会生成代理类
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
return new AbstractProxyInvoker<T>(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<String> getList();
那么生成的代理类如下:
public class Wrapper0 extends com.alibaba.dubbo.common.bytecode.Wrapper
/**
* 属性名, 属性类型
*/
public static java.util.Map pts = new HashMap<String, Class<?>>();
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中进行服务暴露
以上是关于Dubbo使用javassist生成动态类的主要内容,如果未能解决你的问题,请参考以下文章