代理模式
一、模式名
代理, Proxy
二、解决的问题
“代理”这个词我们应该不陌生,在我们的生活中经常使用代理。例如:很多去国外旅游的人都会通过旅游中介公司购买机票、国外景点门票以及规划路线和寻找导游等,其实这就是一种代理模式,把自己不想直接做和不了解的事情交给专业的人去做,这样更加放心,效率也更高。
在软件设计中,同样如此,很多优秀的开发框架都是会使用代理模式。在软件设计中的代理模式主要用于:
1. 安全问题:通过使用代理,可以避免客户端直接访问真实的处理对象,可以控制对象的访问权限;
2. 功能扩展:在很多框架中使用代理来扩展某些功能。比如在Spring中的AOP就利用了代理模式,通过在代理类中织入日志、安全等功能,实现对委托类对象功能的扩展。
三、解决方案
代理模式的UML图如下图所示:
其中Subject为接口,定义需要的方法,代理类ProxySubject和代理类RealSubject都实现Subject接口,同时ProxySubject依赖RealSubject对象完成具体的操作。
具体的代理主要分为两类:静态代理和动态代理。静态代理和动态代理的区别在于静态代理的代理类由程序员编写,代理对象是在通过编译该代理类生成,而动态代理的代理对象是在程序运行时通过反射机制生成。
1. 静态代理
静态代理就是手动编写代理类,代理类通过引用委托类对象完成具体操作。Java代码如下。
interface Subject { void method1(); } RealSubject implements Subject { void method1() { // 实现方法体 ... } } ProxySubject implements Subject { private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } void method1() { // 执行前 before(); // 调用委托类对象完成具体操作 subject.method1(); // 执行后 after(); } void before() {} void after() {} } public class Main { public static void main(String[] args) { Subject subject = new ProxySubject(new RealSubject()); subject.method1(); } }
可以看到静态代理需要针对每个委托类编写一个代理类,如果接口修改,代理类也需要做相应修改。
2. 动态代理
动态代理不需要程序员手动编写代理类,动态代理分为JDK代理和CGLib代理,前者针对其父类是接口的情况,后者针对父类是普通类的情况。
JDK 代理 Java代码如下所示。
public class DynamicProxyHandler implements InvocationHandler { private Object target; public DynamicProxyHandler() { this.obj = target; } public Object invoke(Object obj, Method method, Object[] args) throws Throwable { // before before(); Object result = method.invoke(target, args); // after after(); return result; } void before() {} void after() {} } public class Main { public static void main(String[] args) { Subject subject = new RealSubject(); Subject proxySubject = (Subject) Proxy.newProxyInstance( Main.class.getClassLoader(), new Class[] {Subject.class}, new DynamicProxyHandler(subject)); proxySubject.method1(); } }
其中,Proxy.newProxyInstance()方法有三个参数,桉顺序分别是类加载器,委托类实现的接口,代理类动态处理器。
JDK代理的缺点就是只能针对interface代理,下面CGLib代理使用字节码技术实现针对class的代理。
CGLib 代理 Java代码如下所示。
class Subject { void method1() {} } RealSubject extends Subject { void method1() { // 方法体 ... } } public class CglibProxy implements MethodInterceptor { private Object target; public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperClass(this.target.getClass()); enhancer.setCallBack(this); return enhancer.create(); } public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // before before(); Object object = methodProxy.invoke(target, args); // after after(); return object; } void before(); void after(); } public class Main { public static void main(String[] args) { Subject subject = new RealSubject(); CglibProxy proxy = new CglibProxy(); Subject proxySubject = (Subject) proxy.getInstance(subject); proxySubject.method1(); } }
常见应用场景:
1. Spring中的 AOP