Dubbo使用javassist生成动态类
在服务(本地和远程)暴露的时候会调用proxyFactory.getInvoker方法
具体位置:
- 本地暴露:ServiceConfig#exportLocal line:538
- 远程暴露: ServiceConfig#doExportUrlsFor1Protocol line:512
会先调用AOP织入的类StubProxyFactoryWrapper#getInvoker
然后执行JavassistProxyFactory#getInvoker
JavassistProxyFactory#getInvoker如下
publicInvoker 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); ListgetList();}
那么生成的代理类如下:
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中进行服务暴露