知乎上有一篇极为详细讲解文章!
https://www.zhihu.com/question/20794107/answer/658139129
动态代理分为两大类:
基于接口的动态代理---JDK动态代理
基于类的动态代理--cglib
这里讲的是JDK动态代理,基于接口的。
静态代理时需要我们对每一个类都生成一个代理类,这样代码量及翻倍,且类一旦多起来极其麻烦,这时候需要动态的生成代理对象。
首先需要注意的new关键字,生成一个实例背后,是由一个class对象的。
一个class对象包含了类的所有信息
这时候我们就可以不写代理类,而是通过代理class对象,从而生成一个实例(反射)
这样我们通过传入目标对象,通过目标对象的getclass,就可以动态创建代理对象了
jdk动态代理是基于接口,这时候需要目标类实现一个或一组接口,通过传入这个目标对象的接口(target.getClass().getInterfaces()),来创建代理类实例
JDK提供了一个Proxy类,用来创建代理类实例的,直接使用静态方法newProxyInstance,分别传入此类的加载器,目标类的接口信息,以及InvocationHandler.class
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),InvocationHandler.class);
}
由于接口是无法构建实例,所以传入这个参数InvocationHandler.class
InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法
InvocationHandler这是个接口需要重写invoke方法,proxy对应上面生成代理类,method对应接口方法,args代表的方法参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(target, args);
return invoke;
}
完整代码和测试代码如下,new一个代理类,通过set传入目标类,由于都是实现同一组接口,需要进行接口类强转,在执行接口对应的方法,所以局限就是需要实现接口,且只能代理接口的方法
package com.hys.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态生成代理类
public class myproxy implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(target, args);
return invoke;
}
//测试代码
public static void main(String[] args) {
host host = new host();
myproxy mx = new myproxy();
mx.setTarget(host);
rent proxy = (rent) mx.getProxy();
proxy.rent();
}
}
执行过程如下,会先执行重写的invoke方法,在执行对应接口的方法,即上面对面Object invoke = method.invoke(target, args)这一步,所以可以在invoke里执行自己需要代码。