动态代理,可以理解为在系统运行期间,为目标类生成二进制的class文件并运行,当系统运行完,这个class文件也会消失。dubbo中,每一个spi注解的接口,都会通过动态代理,生成一个类似于ProtocolAdpative的class文件。
动态代理在dubbo的另一个典型应用是proxyFactory。
proxyFactory:
@SPI("javassist")
public interface ProxyFactory {
/**
* create proxy.
*
* @param invoker
* @return proxy
*/
@Adaptive({Constants.PROXY_KEY})
T getProxy(Invoker invoker) throws RpcException;
/**
* create invoker.
*
* @param
* @param proxy
* @param type
* @param url
* @return invoker
*/
@Adaptive({Constants.PROXY_KEY})
Invoker getInvoker(T proxy, Class type, URL url) throws RpcException;
}
是一个接口,用于在服务提供端,将服务的具体实现类转为Invoker。而在消费端,通过 getProxy(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 extends Node {
/**
* get service interface.
*
* @return service interface.
*/
Class getInterface();
/**
* invoke.
*
* @param invocation
* @return result
* @throws RpcException
*/
Result invoke(Invocation invocation) throws RpcException;
}
invoke接口有一个实现的类AbstractInvoker
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 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 Invoker getInvoker(T proxy, Class type, URL url) {
// TODO Wrapper类不能正确处理带$的类名
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);
}
};
}
其重点在于 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(c),通过服务的实现类,生成动态代理类。
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> pts = new HashMap>(); //
Map ms = new LinkedHashMap(); //
List mns = new ArrayList(); // method names.
List 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 )
{
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 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 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 Invoker getInvoker(T proxy, Class type, URL url) {
return new AbstractProxyInvoker(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 getProxy(Invoker 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 getProxy(Invoker 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 getProxy(Invoker invoker, Class>[] interfaces) {
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
目前还没有分析,这里的Proxy.getProxy是使用javassist动态代理实现的。最终的结果应该也是 return invoker.invoke(new RpcInvocation(method, args)).recreate();吧