二Dubbo设计基础--2Wrapper
二Dubbo设计基础--2Wrapper
2.2 Dubbo中Wrapper
注意,区别Dubbo中Wrapper.getWrapper和wrapper机制。前者用在provider端构造invoker时,javassist字节码方式,构建字节码——>>class对象——>>反射创建实例,构造目标服务类的proxy代理对象;
后者是用在SPI获取自动拓展时,为拓展类增加wrapper包裹得到的XXXWrapper类,是dubbo中AOP功能的实现。
2.2.1 Wrapper.getWrapper
2.2.1.1 Wrapper类
Wapper是一个包装类。主要用于“包裹”目标类,仅可以通过getWapper(Class)方法创建子类。在创建子类过程中,子类代码会对传进来的Class对象进行解析,拿到类方法,类成员变量等信息。而这个包装类持有实际的扩展点实现类。也可以把扩展点的公共逻辑全部移到包装类中,功能上就是作为AOP实现。
/**
* get wrapper.
*
* @param c Class instance.
* @return Wrapper instance(not null).
*/
public static Wrapper getWrapper(Class<?> c) {
while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
c = c.getSuperclass();
if (c == Object.class)
return OBJECT_WRAPPER;
Wrapper ret = WRAPPER_MAP.get(c);
if (ret == null) {
ret = makeWrapper(c);
WRAPPER_MAP.put(c, ret);
}
return ret;
}
wrapper.getWrapper生成的类,把目标类所有方法,全部放在invokeMethod方法中,
invoker.doInvoke(wrapper.invokeMethod);//invoker对provider服务实现类的调用逻辑
调用方法,根据方法名称,从wrapper的invokeMethod内,找到对应的方法执行。
2.2.1.2 wrapper.getWrapper实现
wrapper的创建和使用,详细见[6.3.2.1 Provider端Invoker](#6.3.2.1 Provider端Invoker)
跟入Wrapper源码:
//传入的参数Class为provider端对外提供服务的service实现类
private static Wrapper makeWrapper(Class<?> c){
//如果class为基本类型,抛异常
if( c.isPrimitive() )
throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
String name = c.getName();
ClassLoader cl = ClassHelper.getCallerClassLoader(Wrapper.class);
//存储setPropertyValue属性设置的代码
StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
//存储getPropertyValue获取属性的代码
StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
//存储invokeMethod(调用目标类方法)方法
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); }");
该处,传入makeWrapper的类为服务实现类serviceImpl。
执行完上面代码,构造的结果如下(构建目标proxy的代码段,可快速大致看)
c3=public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException{
com.alibaba.dubbo.demo.impl.DemoServiceImpl w;
try{
//该处就是添加类型转换代码的位置
w = ((com.alibaba.dubbo.demo.impl.DemoServiceImpl)$1);
}catch(Throwable e){
throw new IllegalArgumentException(e);
}
继续,
//存储成员变量name:type
Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
//存储方法name:Method对象
Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
//存储方法names
List<String> mns = new ArrayList<String>(); // method names.
//存储当前类声明的方法names
List<String> dmns = new ArrayList<String>(); // declaring method names.
/** ——————————————————————————————对proxy中属性的处理——————————————————————————————-*/
// 对service类中属性处理
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);
}
/** --——————————————————————proxy内方法处理—————————————————————————————— */
//proxy服务提供类内method对象(此时包含所有方法,包括object内方法)
Method[] methods = c.getMethods();
boolean hasMethod = hasMethods(methods);
if( hasMethod ){
c3.append(" try{");
}
for( Method m : methods ){
//如果声明当前方法的类为,object.class,跳过该方法(不处理object继承的方法)
if( m.getDeclaringClass() == Object.class ) //ignore Object's method.
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 ) {
//判定当前m,在method中有没有override方法
if (m != m2 && m.getName().equals(m2.getName())) {
override = true;
break;
}
}
//当m有override方法时
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(" ) { ");
//当前method返回类型为void时
if( m.getReturnType() == Void.TYPE )
c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
else//当前method返回类型非void
c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
c3.append(" }");
//mns、dmns维护
mns.add(mn);
if( m.getDeclaringClass() == c ) //如果method的声明类,是当前类(表示当前类中声明的方法)
dmns.add(mn);
ms.put(ReflectUtils.getDesc(m), m);
}
此时,针对serviceImpl中getPermission方法,生成的方法(wrapper会把目标类中所有的方法全部放在invokeMethod中。如果多个方法,会再invokeMethod中根据方法名,选择对应的方法调用)。此时构造的字符串如下:
//c3字符串
//第一个参数为provider服务实现类,第二个参数为方法名methodName,第三个为参数类型,第四个为方法参数
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException{
com.alibaba.dubbo.demo.impl.DemoServiceImpl w;
try{
//服务真实实现类
w = ((com.alibaba.dubbo.demo.impl.DemoServiceImpl)$1);
}catch(Throwable e){
throw new IllegalArgumentException(e);
}
try{
if( "getPermissions".equals( $2 ) && $3.length == 1 ) {
//调用服务实现类真实方法
return ($w)w.getPermissions((java.lang.Long)$4[0]);
}
继续,(跳过get、set方法处理,比较常规,可以自行debug跟着代码查看)
// make class
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
//通过ClassGenerator为上述过程生成的代码,创建class类,然后根据class反射创建对象——javassist生成类
ClassGenerator cc = ClassGenerator.newInstance(cl);
跟进ClassGenerator类,
public static ClassGenerator newInstance(ClassLoader loader)
{
return new ClassGenerator(getClassPool(loader));
}
//javassist创建字节码的服务类ClassPool
public static ClassPool getClassPool(ClassLoader loader)
{
if( loader == null )
return ClassPool.getDefault();
ClassPool pool = POOL_MAP.get(loader);
if( pool == null )
{
pool = new ClassPool(true);
pool.appendClassPath(new LoaderClassPath(loader));
POOL_MAP.put(loader, pool);
}
return pool;
}
然后继续跟getWrapper,
// make class
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();//自增id,用来命名wrapper类
//通过ClassGenerator为上述过程生成的代码,创建class类,然后根据class反射创建对象——javassist生成类
ClassGenerator cc = ClassGenerator.newInstance(cl);
cc.setClassName( ( Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw" ) + id ); //com.alibaba.dubbo.common.bytecode.Wrapper1
//设置生成包装类的父类
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
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());
//反射创建目标对象proxy的wrapper包装类
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();
}
}
}
上述过程,通过Dubbo自己的ClassGenerator,其初始化通过获取javassist的ClassPool工具类,然后在getWrapper中,对构建的字节码转换为Class对象,然后反射创建实例对象。
2.2.2 Wrapper机制
//todo