dubbo中使用动态代理
Posted qiaozhuangshi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dubbo中使用动态代理相关的知识,希望对你有一定的参考价值。
dubbo的动态代理也是只能代理接口
源码入口在JavassistProxyFactory中
public class JavassistProxyFactory extends AbstractProxyFactory
@Override
@SuppressWarnings("unchecked")
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces)
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url)
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
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);
;
先写个demo
接口
public interface BasePerson
void doSth() ;
String getSth() ;
接口实现类
public class Person implements BasePerson
@Override
public void doSth()
System.out.println("Person 正在 努力工作");
@Override
public String getSth()
System.out.println("person 正在 获取报酬");
return "good men";
写一个InvocationHandler
public class MyInvocationHandler implements InvocationHandler
Object targetObj;
public MyInvocationHandler(Object obj)
targetObj = obj;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
System.out.println("代理前置");
Object invoke = method.invoke(targetObj, args);
System.out.println("代理后置");
return invoke;
测试类
public class ProxyTest
public static void main(String[] args)
Person person = new Person();
Class<?>[] interfaces = Person.class.getInterfaces();
BasePerson proxyperson = (BasePerson) Proxy.getProxy(interfaces).newInstance(new MyInvocationHandler(person));
String sth = proxyperson.getSth();
System.out.println(sth);
控制台打印
代理前置
person 正在 获取报酬
代理后置
good men
源码分析
ClassHelper
// 优先获取当前线程的类加载器
public static ClassLoader getClassLoader(Class<?> cls)
ClassLoader cl = null;
try
cl = Thread.currentThread().getContextClassLoader();
catch (Throwable ex)
// Cannot access thread context ClassLoader - falling back to system class loader...
if (cl == null)
//没有线程上下文的类加载器,使用接口的类加载器
cl = cls.getClassLoader();
return cl;
Proxy
public static Proxy getProxy(Class<?>... ics)
//先获取类加载器
return getProxy(ClassHelper.getClassLoader(Proxy.class), ics);
Proxy 主要是这个方法
public static Proxy getProxy(ClassLoader cl, Class<?>... ics)
if (ics.length > 65535)
throw new IllegalArgumentException("interface limit exceeded");
//记载被代理类接口
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ics.length; i++)
String itf = ics[i].getName();
if (!ics[i].isInterface())
throw new RuntimeException(itf + " is not a interface.");
Class<?> tmp = null;
try
tmp = Class.forName(itf, false, cl);
catch (ClassNotFoundException e)
//当前使用的类加载器加载不到(所以一般用接口自己的类加载器加载)
if (tmp != ics[i])
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
sb.append(itf).append(';');
// 接口集的名字作为key
String key = sb.toString();
// 使用类加载器获取缓存
Map<String, Object> cache;
synchronized (ProxyCacheMap)
cache = ProxyCacheMap.get(cl);
if (cache == null)
cache = new HashMap<String, Object>();
ProxyCacheMap.put(cl, cache);
Proxy proxy = null;
synchronized (cache)
do
// 从缓存中获取
Object value = cache.get(key);
if (value instanceof Reference<?>)
proxy = (Proxy) ((Reference<?>) value).get();
if (proxy != null)
return proxy;
if (value == PendingGenerationMarker)
try
cache.wait();
catch (InterruptedException e)
else
// 添加到缓存(value是一个标识)
cache.put(key, PendingGenerationMarker);
break;
while (true);
//自增id
long id = PROXY_CLASS_COUNTER.getAndIncrement();
//以下就是使用javassist拼装代理类
String pkg = null;
ClassGenerator ccp = null, ccm = null;
try
ccp = ClassGenerator.newInstance(cl);
Set<String> worked = new HashSet<String>();
List<Method> methods = new ArrayList<Method>();
for (int i = 0; i < ics.length; i++)
if (!Modifier.isPublic(ics[i].getModifiers()))
String npkg = ics[i].getPackage().getName();
if (pkg == null)
pkg = npkg;
else
if (!pkg.equals(npkg))
throw new IllegalArgumentException("non-public interfaces from different packages");
ccp.addInterface(ics[i]);
for (Method method : ics[i].getMethods())
String desc = ReflectUtils.getDesc(method);
if (worked.contains(desc))
continue;
worked.add(desc);
int ix = methods.size();
Class<?> rt = method.getReturnType();
Class<?>[] pts = method.getParameterTypes();
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for (int j = 0; j < pts.length; j++)
code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
if (!Void.TYPE.equals(rt))
code.append(" return ").append(asArgument(rt, "ret")).append(";");
methods.add(method);
ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
if (pkg == null)
pkg = PACKAGE_NAME;
// create ProxyInstance class.
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]InvocationHandler.class, new Class<?>[0], "handler=$1;");
ccp.addDefaultConstructor();
Class<?> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
// create Proxy class.
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h) return new " + pcn + "($1); ");
Class<?> pc = ccm.toClass();
proxy = (Proxy) pc.newInstance();
catch (RuntimeException e)
throw e;
catch (Exception e)
throw new RuntimeException(e.getMessage(), e);
finally
// release ClassGenerator
if (ccp != null)
ccp.release();
if (ccm != null)
ccm.release();
synchronized (cache)
if (proxy == null)
cache.remove(key);
else
cache.put(key, new WeakReference<Proxy>(proxy));
cache.notifyAll();
return proxy;
得到编译的class文件
//如果接口是public修饰的 就在debug的时候使用这个能在E盘下生成class文件,e:/com/alibaba/dubbo/common/bytecode/proxy0/proxy0.class
ccm.getClassPool().get("com.alibaba.dubbo.common.bytecode.proxy0").debugWriteFile("e:\\\\")
//如果接口没有被public修饰 debug的时候可以用以下方式获取class文件
ccp.getClassPool().get("per.qiao.util.proxy0").debugWriteFile("e:\\\\")
ccm.getClassPool().get("per.qiao.util.proxy0").debugWriteFile("e:\\\\")
debug截图
编译后的文件proxy0.class
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator.DC;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import per.qiao.util.BasePerson;
public class proxy0 implements DC, BasePerson
public static Method[] methods;
private InvocationHandler handler;
public String getSth()
Object[] var1 = new Object[0];
Object var2 = this.handler.invoke(this, methods[0], var1);
return (String)var2;
public void doSth()
Object[] var1 = new Object[0];
this.handler.invoke(this, methods[1], var1);
public proxy0()
public proxy0(InvocationHandler var1)
this.handler = var1;
以上是关于dubbo中使用动态代理的主要内容,如果未能解决你的问题,请参考以下文章