下面是我写的一个小demo,先来看代码
package com.csdn.demo;
import com.zhang.jian.zhang;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by zhang on 2016/12/16.
* 定义Person接口
*/
interface Person {
String say(String name);
}
/**
*定义Student接口
*/
interface Student{
String study(String name);
}
/**
* Created by zhang on 2016/12/16.
* 定义User类实现Person 和 Student 接口,重写接口方法
*/
class User implements Person,Student {
public String study(String name) {
System.out.println("User正在学习:"+name);
return name;
}
public String say(String name) {
System.out.println("Person的say方法:" + name);
return name;
}
}
/**
* Created by zhang on 2016/12/16.
* 定义 嗯... 我管它叫调用处理器
* 这个主要是用到invoke()方法,作用后面详细介绍
*/
class MyInvocationHandler implements InvocationHandler {
Object obj = null;
/**
* Created by zhang on 2016/12/16.
* 这个方法起到了两个作用
* 1、给obj赋值,将被代理类赋值给obj
* 2、该方法返回一个 实现了被代理类实现的所有接口 的代理类,或者说它返回一个代理类-->被代理类实现的那些
* 接口-->生成的代理类也都实现了(具体后面介绍)
*/
public Object blind(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
/**
* Created by zhang on 2016/12/16.
* invoke方法的作用:生成的代理类要重写实现的接口的方法,重写的方法就是来调用这个invoke()方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入了invoke方法了!");
Object returnValue = method.invoke(obj, args);
return returnValue;
}
}
public class TestProxy {
public static void main(String[] args) {
User user=new User();
MyInvocationHandler handler = new MyInvocationHandler();
Student personProxy = (Student) handler.blind(user);
personProxy.study("Tom");
}
}
运行结果:
进入了invoke方法了!
User正在学习:Tom
Process finished with exit code 0
下面我们来好好分析一下代理类的生成过程
a)调用Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
这条语句生成代理类。
第一个参数:传入被代理类的类类加载器
第二个参数:传入被代理类实现的所有接口
第三个参数:this也就是我们写的那个调用处理器
(如果你对这里有疑虑的话,建议先去看看Class的相关内容:只简单说一下通过Class可以在运行时得到一个类的完整结构)
然后我们点开Proxy的源码文件,发现newProxyInstance方法有如下一条语句
Class<?> cl = getProxyClass(loader, interfaces);
紧接着
Constructor cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[] { h });
不难看出它是通过getProxyClass(loader,interfaces)//loader是传入的类加载器,interfaces是传入的所有接口---
方法返回了一个实现了所有接口的代理类的Class,即这么个东西Class<T>
,其中T就是代理类。
b)我们继续去看getProxyClass(loader,interfaces)
,发现它用到了一个这样的数据类型
static Map<ClassLodar,Map<List<String>,Object>>
,通过读代码我们发现这是Proxy用来缓存代理类的,ClassLoader不用说了就是类加载器,List<String>
保存的是传入的所有接口的名字,而对应的代理类就保存在Object中。
根据你的传入参数,来判断如果之前已经生成了相应的代理类就直接拿出来返回。
如果没有生成过这样的代理类就调用如下一条语句来生成,并把它缓存起来
//proxyClass就是返回结果,所以Class<T>是通过这个方法生成的
proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
//好吧,这个方法是这样定义的,是的我们看到了native关键字,说明这个方法的实现并不是用java写的
//~那么进行到这里就先结束了(已经懒得再去找了)因为我们已经完全可以进行一下合理的推断了~
private static native Class defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
c)到这里我们已经大体知道代理类是如何生成的了,只是一些细节还不清楚,但是通过程序的运行结果我们可以来合理的推断。
- 当我们运行上面程序中的代理类personProxy.study("Tom")
时,执行的是调用处理器的invoke方法
- 在创建代理类的时候我们传入了一个参数this,也就是调用处理器。生成代理类是这样一条语句return cons.newInstance(new Object[] { h });
- 以上两点,说明生成的代理类有一个构造方法,参数就是一个调用处理器的列表,因此我们也可以推断,代理类的方法的实现就是调用了调用处理器的invoke方法,因此我们只要重写invoke方法就是间接实现了代理类的方法。这就是JDK暴露给我们的一个接口。
到了这里我们是不是对AOP面向切面编程有了初步的认识呢?在调用处理器的invoke方法中如果我们在Object returnValue = method.invoke(obj, args);
的上面和下面写点什么东西,是不是就等于在上下两个代码段之间可以动态插入代码了呢?
待更新…