最开始并没有接触过jdk动态的代理的概念,只是在学习spring AOP时知道AOP底层也是用的JDK的动态代理实现的,对于aop也只是知道怎么用,但具体怎么实现的,一直没去考究过。今天终于在看了一些参考资料后硬逼着自己把jdk的动态代理的来龙去脉理解研究了一番。并记载下来以求加深印象。
对于动态代理可以理解为:在程序运行中,程序把我们对目标对象A的访问转移到对代理对象B的访问,因为代理对象B通过一些手段拿到目标对象的方法。
自己定义了四个类:

首先得定义一个接口,必须得这样(到后面就知道道理了)
public interface AppleDao {
void eat();
}
再定义一个实现类
public class AppleDaoImpl implements AppleDao{
@Override
public void eat() {
System.out.println("i want to eat");
}
}
再定义一个MyInvocationHandler实现InvocationHandler接口
public class MyInvocationHandler implements InvocationHandler {
//目标对象
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----before");
System.out.println(this);
Object s= method.invoke(target, args);
System.out.println("----after");
return s;
}
}
在这个类里面我在目标方法调用前后分别打印“—-before”和“—-after”
说了这么多,这么目标对象我们已经知道了就是 AppleDaoImpl ,但是代理对象呢?它在哪里?
通过网上查找发现了有这样的方法,可以在程序运行时拿到在运行时生成的类。
public class ProxyGeneratorUtils {
public static void writeProxyClassToHardDisk(String path){
byte[] classFile = ProxyGenerator.
generateProxyClass("$Proxy12", AppleDaoImpl.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这样所有的准备工作都已经做完了。写一个main方法来测试下:
AppleDao appleDao=new AppleDaoImpl();
MyInvocationHandler m=new MyInvocationHandler(appleDao);
AppleDao proxy=(AppleDao)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
appleDao.getClass().getInterfaces(),
m);
proxy.eat();
ProxyGeneratorUtils.writeProxyClassToHardDisk("d:/$Proxy12.class");
首先控制台会打印:
----before
com.jsm.MyInvocationHandler@66bfa709
i want to eat
----after
然后在d盘中会生成一个文件,我们用反编译工具打开这样一个文件
import com.jsm.AppleDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy12 extends Proxy
implements AppleDao
{
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
public $Proxy12(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 (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void eat()
throws
{
try
{
**this.h.invoke(this, m3, null);**
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.jsm.AppleDao").getMethod("eat", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", 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());
}
}
}
现在我们应该明白一些了,代理类就是 $Proxy12 ,它的构造函数会传入一个InvocationHandler 类型的参数,就是我们之前定义的 MyInvocationHandler。因为proxy类中有一个InvocationHandler h属性。代理类继承了Proxy类,同时也实现了AppleDao接口。在实现的eat方法中this.h.invoke(this, m3, null);通过调用我们自定义的MyInvocationHandler类的invoke方法,从而实现在目标方法调用前和调用后完成我们需要干的事情。
这里再回过头来分析下代理类。它实现了AppleDao 接口,(和目标类实现同样的接口),定义一个InvocationHandler 负责去做具体的事情。我们的业务逻辑就包含在这里面,然后代理类负责调用方法执行,完成预期的任务。
非常期待能和各位志同道合者交流讨论,本人QQ 975907209.