代 理 模 式
目录
- 楔子
- 静态代理
- 基于反射的动态代理
楔子
学习笔记
代理模式(Proxy Pattern)是指建立在某一个对象的代理对象,并且由代理对象控制对象的引用。
例如,我们不能直接访问对象A,则可以建立对象A的代理对象A Proxy。这样可以通过访问A Proxy类间接地使用对象A的功能,A Proxy就像A的对外联络人一般,如下图
代理模式能够实现很多功能:
- 隔离功能:通过建立一个目标对象的代理对象,可以防止外部对象对目标对象的直接访问,这样就使得目标对象与外部隔离。我们可以在代理对象中增加身份验证、权限验证等功能,从而实现目标对象的安全防护。
- 扩展功能:对一个目标对象建立代理对象后,可以在代理对象中增加更多的扩展功能。
- 直接替换:对一个目标对象建立代理对象后,可以直接使用代理对象完全替换目标对象,由代理对象来实现全部功能。例如,MyBatis中数据库操作只是一个抽象方法,但实际运行中会建立代理对象来完成数据库的读写操作。
静态代理
静态代理就是代理模式最简单的实现。所谓“静态”,是指被代理对象和dialing对象在程序中是确定的,不会在程序运行过程中发生变化。
例如,为用户设置一个接口类UserInterface,增加一个大招呼的抽象方法sayHello。
public interface UserInterface {String sayHello(String name);
}
实现UserInterface接口的被代理类如下
public class User implements UserInterface {@Overridepublic String sayHello(String name) {System.out.println("hello " + name);return "OK";}
}
为代理类增加一个代理类。代理类中调用了被代理类的sayHello方法,并在此方法的基础上增加新功能。
public class UserProxy implements UserInterface{private UserInterface target;public UserProxy(UserInterface target) {this.target = target;}@Overridepublic String sayHello(String name) {System.out.println("pre words");target.sayHello(name);System.out.println("post words");return name;}
}
使用代理对象中的方法
public void testProxy() {//生成被代理对象User user = new User();//生成代理UserProxy userProxy = new UserProxy(user);//触发代理方法userProxy.sayHello("静态代理");
}
基于反射的动态代理
静态代理中代理对象和被代理对象是在程序中写死的,不够灵活。
java中java.lang.reflect包提供了一个Proxy和InvocationHandler接口,使用它们就可以实现动态代理。
如下代理是基于反射的动态代理
接口代码如下
public interface UserInterface {String sayHello(String name);
}
被代理类如下
public class User implements UserInterface {@Overridepublic String sayHello(String name) {System.out.println("hello " + name);return "OK";}
}
以下创建一个ProxyHander类继承java.lang.reflect.InvocationHandler接口,并实现其中的invoke方法,invoke方法中需要传入被代理对象、被代理方法及调用代理方法所需的参数。
public class ProxyHandler<T> implements InvocationHandler {private T target;public ProxyHandler(T target) {this.target = target;}/*** @param proxy 被代理的对象* @param method 要调用的方法* @param args 方法调用时所需要参数* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("pre words");Object ans = method.invoke(target, args);System.out.println("post words");return ans;}
}