网络异常,图片无法展示
|
今天谈谈 Dubbo 的 org.apache.dubbo.common.bytecode.Wrapper 类
Dubbo 依赖该工具在服务提供者端接收处理请求的时候、直接调用提供服务的 service 相对于传统的反射、性能其实有很大的提升
private static Wrapper makeWrapper(Class<?> c) { String name = c.getName(); ClassLoader cl = ClassUtils.getClassLoader(c); StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ "); StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ "); StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ "); c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }"); c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }"); c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }"); Map<String, Class<?>> pts = new HashMap<>(); // <property name, property types> Map<String, Method> ms = new LinkedHashMap<>(); // <method desc, Method instance> List<String> mns = new ArrayList<>(); // method names. List<String> dmns = new ArrayList<>(); // declaring method names. // get all public field. for (Field f : c.getFields()) { String fn = f.getName(); Class<?> ft = f.getType(); if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) { continue; } c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }"); c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }"); pts.put(fn, ft); } Method[] methods = c.getMethods(); // get all public method. boolean hasMethod = hasMethods(methods); if (hasMethod) { c3.append(" try{"); for (Method m : methods) { //ignore Object's method. if (m.getDeclaringClass() == Object.class) { continue; } String mn = m.getName(); c3.append(" if( \"").append(mn).append("\".equals( $2 ) "); int len = m.getParameterTypes().length; c3.append(" && ").append(" $3.length == ").append(len); boolean override = false; for (Method m2 : methods) { if (m != m2 && m.getName().equals(m2.getName())) { override = true; break; } } if (override) { if (len > 0) { for (int l = 0; l < len; l++) { c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"") .append(m.getParameterTypes()[l].getName()).append("\")"); } } } c3.append(" ) { "); if (m.getReturnType() == Void.TYPE) { c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;"); } else { c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");"); } c3.append(" }"); mns.add(mn); if (m.getDeclaringClass() == c) { dmns.add(mn); } ms.put(ReflectUtils.getDesc(m), m); } c3.append(" } catch(Throwable e) { "); c3.append(" throw new java.lang.reflect.InvocationTargetException(e); "); c3.append(" }"); } c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }"); // deal with get/set method. Matcher matcher; for (Map.Entry<String, Method> entry : ms.entrySet()) { String md = entry.getKey(); Method method = entry.getValue(); if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) { String pn = propertyName(matcher.group(1)); c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }"); pts.put(pn, method.getReturnType()); } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) { String pn = propertyName(matcher.group(1)); c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }"); pts.put(pn, method.getReturnType()); } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) { Class<?> pt = method.getParameterTypes()[0]; String pn = propertyName(matcher.group(1)); c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }"); pts.put(pn, pt); } } c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }"); c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }"); // make class long id = WRAPPER_CLASS_COUNTER.getAndIncrement(); ClassGenerator cc = ClassGenerator.newInstance(cl); cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id); cc.setSuperClass(Wrapper.class); cc.addDefaultConstructor(); cc.addField("public static String[] pns;"); // property name array. cc.addField("public static " + Map.class.getName() + " pts;"); // property type map. cc.addField("public static String[] mns;"); // all method name array. cc.addField("public static String[] dmns;"); // declared method name array. for (int i = 0, len = ms.size(); i < len; i++) { cc.addField("public static Class[] mts" + i + ";"); } cc.addMethod("public String[] getPropertyNames(){ return pns; }"); cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }"); cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }"); cc.addMethod("public String[] getMethodNames(){ return mns; }"); cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }"); cc.addMethod(c1.toString()); cc.addMethod(c2.toString()); cc.addMethod(c3.toString()); try { Class<?> wc = cc.toClass(); // setup static field. wc.getField("pts").set(null, pts); wc.getField("pns").set(null, pts.keySet().toArray(new String[0])); wc.getField("mns").set(null, mns.toArray(new String[0])); wc.getField("dmns").set(null, dmns.toArray(new String[0])); int ix = 0; for (Method m : ms.values()) { wc.getField("mts" + ix++).set(null, m.getParameterTypes()); } return (Wrapper) wc.newInstance(); } catch (RuntimeException e) { throw e; } catch (Throwable e) { throw new RuntimeException(e.getMessage(), e); } finally { cc.release(); ms.clear(); mns.clear(); dmns.clear(); } } 复制代码
其实这段代码就是动态生成一个包装类、生成的类继承 org.apache.dubbo.common.bytecode.Wrapper
主要涉及有三个方法
- getPropertyValue
- invokeMethod
- setPropertyValue
生成的类其实是
public class TestWrapper { private String name; private Integer age; public String address; public String sayHi(){ return "hi"; } public String sayGoodbye() { return "bye"; } } 复制代码
看下生成的 Wrapper 对象
package org.apache.dubbo.common.bytecode; public class Wrapper0 extends Wrapper { /** * property name array. */ public static String[] pns; /** * property type map. */ public static Map pts; /** * all method name array. */ public static String[] mns; /** * declared method name array. */ public static String[] dmns; public static Class[] mts0; //存放方法的参数类型 public static Class[] mts1; // 存放方法的参数类型 public String[] getPropertyNames(){ return pns; } public boolean hasProperty(String n){ return pts.containsKey(n); } public Class getPropertyType(String n){ return (Class)pts.get(n); } public String[] getMethodNames(){ return mns; } public String[] getDeclaredMethodNames(){ return dmns; } public Object getPropertyValue(Object o, String n) { TestWrapper w; try { w = ((TestWrapper) $1); } catch (Throwable e) { throw new IllegalArgumentException(e); } if ($2.equals("address")) { return ($w) w.address; } throw new org.apache.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + $2 + "\" field or setter method in class TestWrapper."); } public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException { TestWrapper w; try { w = ((TestWrapper) $1); } catch (Throwable e) { throw new IllegalArgumentException(e); } try { if ("sayHi".equals($2) && $3.length == 0) { return ($w) w.sayHi(); } if ("sayGoodbye".equals($2) && $3.length == 0) { return ($w) w.sayGoodbye(); } } catch (Throwable e) { throw new java.lang.reflect.InvocationTargetException(e); } throw new org.apache.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + $2 + "\" in class TestWrapper."); } public void setPropertyValue(Object o, String n, Object v) { TestWrapper w; try { w = ((TestWrapper) $1); } catch (Throwable e) { throw new IllegalArgumentException(e); } if ($2.equals("address")) { w.address = (java.lang.String) $3; return; } throw new org.apache.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + $2 + "\" field or setter method in class TestWrapper."); } } 复制代码
- getPropertyValue 能获取到的都是申明为 public 的属性
- invokeMethod 能获取到的都是申明为 public 的方法
- setPropertyValue 能获取到的都是申明为 public 的属性
原因简单啊、因为不在同一个包下、生成的这个 Wrapper 类是跟 org.apache.dubbo.common.bytecode.Wrapper 在同一个包中
至于他生成的几个静态变量
网络异常,图片无法展示
|
其实都是为了以后方便获取被包装类的相关信息、比如在 ServiceConfig 的 doExportUrlsFor1Protocol 方法的时候
网络异常,图片无法展示
|
就通过生成一个 Wrapper 获取服务接口暴露出去多少个方法、获取起方法名、放到 map 里面、为后续生成注册的 url 做准备