设计模式(九)_代理模式
2019-07-29

不知不觉今天已经7月底了,时间过得真快,这个月真热,这篇文章主要来介绍代理模式。

概述

代理模式为另一个对象提供一个替身或者占位符以控制对这个对象的访问

如下图所示

UML类图

代理模式类别

代码实现

这里是结合springAop,仿造它的实现

静态代理

public interface Subject { void request();}// 请求的真实目标对象public class RealSubject implements Subject { @Override public void request() { System.out.println("real subject execute request"); }}// 代理对象public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { System.out.println("before"); try { realSubject.request(); } catch (Exception e) { System.out.println("ex:" + e); throw e; } finally { System.out.println("after"); } }}

客户端调用代码

public class Client { public static void main(String[] args) throws Exception { Subject subject = new Proxy(new RealSubject()); subject.request(); }}

运行结果

beforereal subject execute requestafter

静态代理有一个很明显的缺点:代理的方法越多,重复代码越多。就不符合DRY原则。于是 就产生了动态代理

动态代理

jdk代理

JDK 为我们提供了一种动态代理的实现,通过实现 InvocationHandler 接口来实现动态代理。

代理类代码

public class JdkProxySubject implements InvocationHandler { private RealSubject realSubject; public JdkProxySubject(RealSubject realSubject) { this.realSubject = realSubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object result = null; try { result = method.invoke(realSubject, args); } catch (Exception e) { System.out.println("ex" + e); throw e; } finally { System.out.println("after"); } return result; }}

客户端类代码

public class Client { public static void main(String[] args) throws Exception { Subject subject = (Subject) Proxy.newProxyInstance(Client.class .getClassLoader(), new Class[]{Subject.class}, new JdkProxySubject(new RealSubject())); subject.request(); }}

运行结果

beforereal subject execute requestafter

上面讲了动态代理是解决代码重复的问题。我们来验证下

首先,在Subject 接口中增加一个hello方法

public interface Subject { void request(); void hello();}public class RealSubject implements Subject { @Override public void request() { System.out.println("real subject execute request"); } @Override public void hello() { System.out.println("real subject execute hello"); }}

静态代理类 如果想要代理hello 这个方法。就要在代理类中实现这个方法

public class Proxy implements Subject { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void hello() { ... }}

我们看动态代理类,无需改变,直接运行测试类

public class Client { public static void main(String[] args) throws Exception { Subject subject = (Subject) Proxy.newProxyInstance(Client.class .getClassLoader(), new Class[]{Subject.class}, new JdkProxySubject(new RealSubject())); subject.hello(); }}

运行结果

beforereal subject execute helloafter

Cglib代理

代理类

public class DemoMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before in cglib"); Object result = null; try { result = proxy.invokeSuper(object,args); }catch (Exception e){ System.out.println("get ex :" + e.getMessage()); throw e; }finally { System.out.println("after in cglib"); } return result; }}

调用

public class Client { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealSubject.class); enhancer.setCallback(new DemoMethodInterceptor()); Subject subject = (Subject) enhancer.create(); subject.request(); }}

运行结果

before in cglibreal subject execute requestafter in cglib

JDK代理和Cglib代理区别

JDK代理只能针对有接口的类的方法进行代理Cglib基于继承来实现代理,无法对static、final 类进行代理Cglib基于继承来实现代理,无法对private、static 方法 进行代理

代理模式暂时先分析到这,玩的开心!