1. 程式人生 > >dubbo的proxyFactory和動態代理相關

dubbo的proxyFactory和動態代理相關

動態代理,可以理解為在系統執行期間,為目標類生成二進位制的class檔案並執行,當系統執行完,這個class檔案也會消失。dubbo中,每一個spi註解的介面,都會通過動態代理,生成一個類似於Protocol A d p a t i

v e x x x Adpative等的xxx Adpative的class檔案。

動態代理在dubbo的另一個典型應用是proxyFactory。
proxyFactory:

@SPI("javassist")
public interface ProxyFactory {

    /**
     * create proxy.
     * 
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * create invoker.
     * 
     * @param <T>
     * @param proxy
     * @param type
     * @param url
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

是一個介面,用於在服務提供端,將服務的具體實現類轉為Invoker。而在消費端,通過 getProxy(Invoker invoker)將invoker轉為客戶端需要的介面。
在服務的釋出端serviceConfig和消費端ReferenceConfig中,都會對proxyFactory通過ExtensionLoader拓展機制
生成自適應類 ProxyFactory$Adpative(這個類會根據url的ProxyFactory引數選擇對應的實現類進行操作)。

public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory {
    public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2)  {
        if (arg2 == null) 
            throw new IllegalArgumentException("url == null");

        com.alibaba.dubbo.common.URL url = arg2;
        String extName = url.getParameter("proxy", "javassist");
        if(extName == null) 
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");

        com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);

        return extension.getInvoker(arg0, arg1, arg2);
    }

通過檢視com.alibaba.dubbo.rpc.proxy檔案,

stub=com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
jdk=com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory
javassist=com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory

其中,JdkProxyFactory和JavassistProxyFactory是ProxyFactory 的具體擴充套件實現,StubProxyFactoryWrapper是實現了對代理工廠進行裝飾的功能。從ProxyFactory 的介面的註解來看,JavassistProxyFactory是其預設實現。

JavassistProxyFactory的getInvoker方法

x先看看Invoker這個介面,其 Result invoke(Invocation invocation)方法,invocation包含了呼叫的方法以及引數。其通過invoke方法,得到方法的結果。

public interface Invoker<T> extends Node {

    /**
     * get service interface.
     * 
     * @return service interface.
     */
    Class<T> getInterface();

    /**
     * invoke.
     * 
     * @param invocation
     * @return result
     * @throws RpcException
     */
    Result invoke(Invocation invocation) throws RpcException;

}

invoke介面有一個實現的類AbstractInvoker,檢視其invoke方法:

    public Result invoke(Invocation inv) throws RpcException {
        if(destroyed) {
            throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost() 
                                            + " use dubbo version " + Version.getVersion()
                                            + " is DESTROYED, can not be invoked any more!");
        }
        RpcInvocation invocation = (RpcInvocation) inv;
        invocation.setInvoker(this);
        if (attachment != null && attachment.size() > 0) {
        	invocation.addAttachmentsIfAbsent(attachment);
        }
        Map<String, String> context = RpcContext.getContext().getAttachments();
        if (context != null) {
        	invocation.addAttachmentsIfAbsent(context);
        }
        if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)){
        	invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
        }
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
        
        
        try {
            return doInvoke(invocation);
        } catch (InvocationTargetException e) { // biz exception
            Throwable te = e.getTargetException();
            if (te == null) {
                return new RpcResult(e);
            } else {
                if (te instanceof RpcException) {
                    ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
                }
                return new RpcResult(te);
            }
        } catch (RpcException e) {
            if (e.isBiz()) {
                return new RpcResult(e);
            } else {
                throw e;
            }
        } catch (Throwable e) {
            return new RpcResult(e);
        }
    }

上面這個方法,最終會呼叫 return doInvoke(invocation)。而在AbstractInvoker類中,doinvoke是

 protected abstract Result doInvoke(Invocation invocation) throws Throwable;

是需要繼承類實現的。

而在JavassistProxyFactory中,其getInvoker方法通過返回一個新建的AbstractProxyInvoker匿名類,(其類裡實現了doInvoke方法,這個doinvoke方法使得我們在通過)

    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper類不能正確處理帶$的類名
        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);
            }
        };
    }

其重點在於 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(’$’) < 0 ? proxy.getClass() : type); 通過我們的服務實現類,生成一個wrapper類,

	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;
    }

上面的重點在於 makeWrapper©,通過服務的實現類,生成動態代理類。

	private static Wrapper makeWrapper(Class<?> c)
	{
		if( c.isPrimitive() )
			throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

		String name = c.getName();
		ClassLoader cl = ClassHelper.getCallerClassLoader(Wrapper.class);

		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<String, Class<?>>(); // <property name, property types>
		Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
		List<String> mns = new ArrayList<String>(); // method names.
		List<String> dmns = new ArrayList<String>(); // 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 )
		{
			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 ) {
				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);
		}
		if( hasMethod ){
		    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 = (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+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
		c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed 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();
		}
	}

上面這個方法太太太長了,其基本思想就是javassist動態代理的那一套,最終通過Class<?> wc = cc.toClass();生成Class<?>檔案,最後通過(Wrapper)wc.newInstance()進行例項化然後返回。
就看看具體生成什麼類吧,主要看類裡的invokeMethod方法:

public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws
java.lang.reflect.InvocationTargetException{
 cn.andy.dubbo.DataService w; 
 try{
  w= ((cn.andy.dubbo.DataService)$1);
   }catch(Throwable e){
    throw new IllegalArgumentException(e);
     }
   try{
    if( "getStringData".equals( $2 )  &&
$3.length == 0 ) {
  return ($w)w.getStringData();
   }
    if( "dubboTest2".equals( $2)  &&  $3.length == 1 ) {
      return ($w)w.dubboTest2((java.lang.String)$4[0]);
       }
if( "dubboTest".equals( $2 )  &&  $3.length == 1 ) {
  return ($w)w.dubboTest((java.lang.String)$4[0]); 
     }
   } catch(Throwable e) { 
        throw new java.lang.reflect.InvocationTargetException(e);
          } throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method
\""+$2+"\" in class cn.andy.dubbo.DataService.");
 }

而我們的介面是:

public interface DataService {
	
	int dubboTest(String id);
	
	int dubboTest2(String id);
	
	String getStringData();

}

實現類的名稱是
public class DataServiceImpl implements DataService
從上面可以看出,所有呼叫wrapper的invokeMethod方法,都會轉為呼叫我們真正的實現類。這樣,在後期requestHandler 中,呼叫 return invoker.invoke(inv)時,就會呼叫上述的javassist生成的動態代理類,動態代理類最終呼叫我們真正的服務實現類。

JdkProxyFactory的getInvoker方法

    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName, 
                                      Class<?>[] parameterTypes, 
                                      Object[] arguments) throws Throwable {
                Method method = proxy.getClass().getMethod(methodName, parameterTypes);
                return method.invoke(proxy, arguments);
            }
        };
    }

}

JdkProxyFactory的就比較簡單,就是簡單的反射,呼叫我們的真正實現類。

再看看JdkProxyFactory的getProxy方法

首先,不管是JdkProxyFactory還是JavassistProxyFactory,都會先呼叫AbstractProxyFactory的getProxy方法。主要操作,就是增加了一個EchoService.class介面,每個服務都會增加這個介面,保證每個代理都可以使用回聲服務。

  public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        Class<?>[] interfaces = null;
        String config = invoker.getUrl().getParameter("interfaces");
        if (config != null && config.length() > 0) {
            String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
            if (types != null && types.length > 0) {
                interfaces = new Class<?>[types.length + 2];
                interfaces[0] = invoker.getInterface();
                interfaces[1] = EchoService.class;
                for (int i = 0; i < types.length; i ++) {
                    interfaces[i + 1] = ReflectUtils.forName(types[i]);
                }
            }
        }
        if (interfaces == null) {
            interfaces = new Class<?>[] {invoker.getInterface(), EchoService.class};
        }
        return getProxy(invoker, interfaces);
    }
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
    }

這是典型的jdk動態代理的用法,根據介面獲得的動態代理類,其呼叫的介面的方法都會轉而呼叫InvokerInvocationHandler(invoker),

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return invoker.toString();
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return invoker.hashCode();
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return invoker.equals(args[0]);
        }
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }

再看看JavassistProxyFactory的getProxy方法

 public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
       return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
   }

目前還沒有分析,這裡的Proxy.getProxy是使用javassist動態代理實現的。最終的結果應該也是 return invoker.invoke(new RpcInvocation(method, args)).recreate();吧