楔子
学习笔记
代理模式(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 {
@Override
public 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;
}
@Override
public 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 {
@Override
public 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
*/
@Override
public 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;
}
}