参考:https://blog.csdn.net/u013452337/article/details/100535019
什么是代理设计模式
Proxy 代理模式是一种结构型设计模式,其目的就是为某个对象提供一个代理类,以控制对该对象的访问。
代理类主要负责:为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的等后续处理。所以,当两个类需要通信时,代理设计模式通过引入第三方代理类,将两个类的关系解耦,使得程序只要了解代理类即可。 代理设计模式的 UML 类图如下。
静态代理
- 静态代理:通过聚合(或者是用Spring IOC进行注入)来实现,让代理类持有一个委托类的引用即可。
静态代理例子如下:
public interface Subject{
public void checkMoney();
}
public class RealSubject implements Subject{
// 实现接口的方法,专注于核心的代码,其他切面通过代理类织入
public void checkMoney() {
System.out.println("checkMoney().........余额为500");
}
}
public class Proxy implements Subject{
// 注入其他的类,和被代理的类
private LogManage log=new LogManage();
private Quit quit=new Quit();
private SafeCheck check=new SafeCheck();
private RealSubject rs; //被代理类
// 实现接口方法,切面通过其他类的方法调用织入
public void checkMoney() {
check.isSafe(); //前置通知, 先检测安全环境
rs.checkMoney();; //连接点(织入点,目标方法),处理核心业务
log.log(); //后置通知,记录日志
quit.clear(); //后置通知,处理缓存
}
}
缺点:通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,这里只存在一个方法所以工作量还不算大,假如接口中包含上百个方法呢? 这时候使用静态代理就会编写许多冗余代码。那么动态代理就能够解决这个问题。
JDK动态代理
- 动态代理:代理类在程序运行时创建,也就是说,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args);
}
动态代理例子中,Subject和RealSubject和静态代理是一样的,主要区别是代理Proxy类变成了InvocationHandler的子类,例子如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理的使用
*/
interface Subject {
void action();
}
//被代理类
class RealSubject implements Subject {
public void action() {
System.out.println("我是被代理类!");
}
}
//
class MyInvocationHander implements InvocationHandler{
Object obj; // 实现了接口的被代理类的对象的声明
public MyInvocationHander(Object obj){
this.obj = obj;
}
// 返回一个代理类的对象,这个代理(Proxy)对象是动态生成的
public Object getProxyInstance(){
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
//当通过代理类的对象发起对被重写的方法调用时,都会转换为对如下的invoke方法的调用
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method方法的返回值是returnVal
System.out.println("这里织入其他切面");
Object returnVal = method.invoke(obj, args);
System.out.println("这里织入其他切面");
return returnVal;
}
}
class TestProxy {
public static void main(String[] args) {
//1.被代理类的对象
RealSubject real = new RealSubject();
//2.创建一个实现了InvocationHandler接口类的对象
MyInvocationHander hander = new MyInvocationHander(real);
//3.调用blind()方法,动态的返回一个同样实现了real所在类的实现的接口Subject的代理类的对象
Object obj = hander.getProxyInstance();
Subject sub = (Subject)obj; //此时的sub就是代理类的对象
sub.action(); //转到对InvocationHandler接口的实现类的invoke()的调用
}
}
InvocationHandler子类中有两个方法和一个成员
一个成员:Object obj为被代理类(RealSubject )的对象的声明
两个方法:
Object getProxyInstance(Object obj)
返回一个代理类的对象,这个(Proxy)对象是动态生成的
-
Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
该方法用于为指定类装载器、一组接口列表 及 调用处理器(InvocationHandler) 生成动态代理类实例。
– ClassLoader 类装载器
– interfaces 一组接口列表
– InvocationHandler 调用处理器,也就是我们的实现InvocationHandler接口的子类的实例 -
其实getProxyInstance方法可以没有,但是去掉的话就要在测试类中写了,把InvocationHandler参数传入this换成InvocationHandler子类的实例化对象即可。
public Object invoke(Object proxy, Method method, Object[] args)
当通过代理类的对象发起对被重写的方法调用时,都会转换为invoke方法的调用
总体的逻辑:
-
首先新建一个类,实现InvocationHandler接口,传入要被代理的对象实例
-
写一个返回一个代理类对象的方法getProxyInstance(),返回动态代理类对象(其实getProxyInstance方法可以没有,没有的话就要在测试类中写了)
-
重写invoke方法,其中我们调用委托类的相应方法,并且可以添加自己的处理逻辑。
代理模式最大的特点:
- 即多态,即代理类和实际业务类实现同一个接口(或继承同一父类),代理对象持有一个实际对象(RealSubject)的引用,外部调用时操作的是代理(Proxy)对象,而在代理(Proxy)对象的内部实现中又会去调用实际对象(RealSubject)的操作