动态代理的理解
什么是代理?
代理主要实现被代理类的增强处理,在不修改源码的基础上,对原有代码进行一个封装,进一步实现某些增强功能。
代理分为静态代理和动态代理
静态代理:
代理类实现被代理类的接口,在代理类中实例化被代理类,生成一个被代理类对象,重写方法A以实现增强功能,同时在代理类的方法A中,实际是调用了被代理类对象的方法A实现的。
静态代理有一个缺点,即,如果有很多被代理类,则需要生成对应多的代理类对象,难以实现。于是就有了动态代理:
动态代理:
静态代理的过程:被代理类Class→被代理类对象→代理类→代理类对象
假如此时有很多被代理类,而我们主要是为了避免写过多代理类,那么现在的考虑方向为,如何不写代理类,而直接获得代理对象?
不通过类来产生实例,想到可以通过反射来实现。创建实例,需要提供Class对象,如何去获取class对象呢?
这里搁置一个问题,为什么不能直接从被代理类中获取实例化代理对象所需要的信息?
我们知道代理类和被代理类实现同一个接口,因此可以从这个接口中获得相关信息
具体的可以通过两种方法:
1.Proxy类的getProxyClass();然后调用其Constructor对象来进行实例化
2.Proxy类的newProxyInstance();
具体如下:
首先,依旧是之前的接口类和被代理类。我们创建一个PersonInterface接口,其中声明一个say()方法,并用Student来实现并重写say()方法:
public interface PersonInterface {
public void say();
}
public class Student implements PersonInterface{
@Override
public void say(){
System.out.println("start Student.say()");
System.out.println("imStudent");
System.out.println("end Student.say()");
}
}
say()中打印的语句为了后面显示其中的调用结构
随后不创建代理类,而是创建一个handler类。handler类的作用就是进行动态代理调度的。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ProxyHandler01 implements InvocationHandler {
// 这里的object为待传入的被代理类对象
Object object;
public ProxyHandler01(Object object){
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start ProxyHandler's invoke");
System.out.println(method.getName());
method.invoke(object,args);
System.out.println("end ProxyHandler's invoke");
return null;
}
}
先暂时不管这个handler中的invoke()方法的参数,先看一下main中动态代理是如何实现的:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String args[]){
// System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
PersonInterface st = new Student();
InvocationHandler ph = new ProxyHandler01(st);
PersonInterface proxyStudent = (PersonInterface) Proxy.newProxyInstance(
st.getClass().getClassLoader(),
st.getClass().getInterfaces(),
ph);
System.out.println("start proxyStudent.say()");
proxyStudent.say();
System.out.println("end proxyStudent.say()");
}
}
首先创建一个Strudent对象st并声明为PersonInterface;
再创建一个hander对象,并声明为InvocationHandler,同时将st作为参数传入构造函数中,进入handler对象中,st作为handler对象的一个Field存在;
(这里之所以都用接口声明是为体现同一接口下相同的特质;)
然后调用Proxy的newProxyInstance()创建代理实例,其中第一个参数st.getClass().getClassLoader()获取了Student类的类加载器,第二个参数st.getClass().getInterfaces()返回Student类所实现的接口列表,第三个参数ph为一个handler实例,而这个handler实例中封装了st对象。
因此可以认为,Proxy.newProxyInstance()方法通过被代理类加载器,接口信息,st实例对象创建了一个代理实例proxyStudent,调用其say()方法,可以看到输出结果为:
/** 输出结果:
* start proxyStudent.say()
* start ProxyHandler's invoke
* start student.say()
* imStudent
* end student.say()
* end ProxyHandler's invoke
* end proxyStudent.say()
*/
说明,proxyStudent.say()中嵌套了一个handler.invoke()中嵌套了Student.say(),
handler.invoke()相当于proxyStudent.say和Student.say中间的桥梁
handler.invoke内部实际上是调用method.invoke实现的,
handler.invoke的参数为(object,method,object[]),其中这个object就是传入的Student实例st,object[]是接口列表,而这个method对象就是st的say方法,可见代理类实例化所需要的信息都封装在其中了。
调用代理对象proxyStudent的say()方法,内部会调用ph的invoke()方法,而invoke的方法传入method参数调用st的say方法,以此完成代理功能。由于其中的st的say方法嵌套在invoke中,因此可以在invoke中进行编写增强功能代码。
如果此时还有另一个被代理类,只需在main方法中new一个该被代理类对象,然后传参到newProxyInstance中即可实例化对应的代理类。