1、何为代理?
为了增强目标对象(委托对象)功能,在访问目标对象的路径上增加控制访问对象,该对象负责目标对象执行前后的
附加功能, 该访问控制对象即为代理对象, 这种设计模式即为代理!
代理根据代理对象生成的时间分为 静态 和 动态 代理, 本篇我们主要讨论动态代理。
2、主要的动态代理实现
2.1)JDK动态代理
JDK动态代理主要有java.lang.reflect.Proxy类实现,主要的实现的思路如下:
a、生成以Proxy为父类,实现所有代理接口的class对象;
b、调用上述class对象的构造器(以InvocationHandler为入参)实例化代理类;
举个例子,辅助理解一下;
1、定义一个代理接口, 如图
2、定义一个委托类
3、定义一个代理处理器
我们可以根据上述的代理要求利用JDK的动态代理工具类Proxy创建代理类, 设置系统属性 sun.misc.ProxyGenerator.saveGeneratedFiles = true,
在创建代理时, JVM会自动将生成的$Proxy*文件保存到某个默认路径下,一般是项目根路径下的com/sun/proxy 或者 sun/proxy路径下,这个可以根据
具体的错误提示创建对应的路径, 如下是一个工具方法
这里把用工具方法生成的代理类class对象反编译后的类贴出来,分析一下
package sun.proxy;
import com.zhc.service.speaker.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
implements Subject
{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final void speak()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("com.zhc.service.speaker.Subject").getMethod("speak", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
可以重点看一下上述类实现, 代理类实际上通过反射 m3 = Class.forName("com.zhc.service.speaker.Subject").getMethod("speak", new Class[0]);
获取委托对象的实现方法Method对象,然后通过实现的接口方法 public final void speak()统一调用InvocationHandler的invoke方法, 那Invocationhandler
是如何传入的呢,没错就是通过代理类的带参构造器 public $Proxy0(InvocationHandler paramInvocationHandler),这里可以看一下具体的Proxy
代码实现,如图
2.2)Dubbo的自实现的动态代理
其实Dubbo自己实现的代理类生成机制和JDK思路是一样的,不过Dubbo没有用sun.misc.*包中的API方法,可能框架设计者不想让Dubbo太依赖
JDK的底层实现吧, 现在分析一下:
a) 通过代理接口组装代理类;
b) 构建代理类的代理;
c) 通过实例化接口,创建代理类实例;
Dubbo实现了自己的类生成器com.alibaba.dubbo.common.bytecode.ClassGenerator ,有兴趣可以分析一下,不展开了!
我直接贴代码分析吧, 这样直观一些,如图
构建代理类的代理实例,如图
总结一下上述创建过程, Dubbo会首先根据代理接口生成代理类的Class对象$Proxy.class,然后在创建一个Proxy的子类,该类实现了真正的创建代理类$Proxy
的方法,然后客户通过调用该方法,返回委托对象的代理类,同时传入业务相关的InvacationHandler类型处理器。
好了就啰嗦这么多吧。
尊重每一个坚持改变,让现状变得更好的人!!