简介
定义
代理模式定义:给某一个对象提供一个代理,通过代理来控制对该对象的引用。
相关角色
Subject: 抽象主题角色接口。是RealSubject和Proxy的共用接口。
RealSubject: 真实主题角色,实现了Subject接口。
Proxy: 代理角色,内部有RealSubject的引用,因此可操作RealSubject。同时代理对象提供了真实对象拥有的接口,因此在任何时刻都能替代RealSubject。并且通过代理对象执行RealSubject的操作前后进行处理。
代理类型:
1.静态代理
静态代理由程序员创建或由特定工具自动生成代理类的源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
实现静态代理的两种方法:
聚合式静态代理
聚合式静态代理模式UML类图
实现代码:
/** * Subject * 抽象主题接口 * @author * @create 2018-03-29 14:16 **/ public interface Subject { void doSomething(); }
/** * RealSubject * 真实主题类 * @author * @create 2018-03-29 14:21 **/ public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something"); } }
/** * Proxy * 代理类 * @author * @create 2018-03-29 14:22 **/ public class Proxy implements Subject { // 以聚合方式实现代理 private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void doSomething() { System.out.println("Do something before"); realSubject.doSomething(); System.out.println("Do something after"); } }
/** * Client * client测试代码 * @author * @create 2018-03-29 14:26 **/ public class Client { public static void main(String[] args) { // 聚合式静态代理测试 RealSubject realSubject = new RealSubject(); Proxy proxy = new Proxy(realSubject); proxy.doSomething(); } }
继承式静态代理
继承式静态代理模式UML类图
实现代码:
抽象主题接口类Subject和真实主题类RealSubject与聚合方式中的相同,不再复制。
/** * Proxy2 * 代理类 * @author * @create 2018-03-29 15:02 **/ public class Proxy2 extends RealSubject { @Override public void doSomething() { System.out.println("Do something before"); super.doSomething(); System.out.println("Do something after"); } }
/** * Client * client测试代码 * @author * @create 2018-03-29 14:26 **/ public class Client { public static void main(String[] args) { // 继承式静态代理测试 Proxy2 proxy2 = new Proxy2(); proxy2.doSomething(); } }
聚合方式先比继承方式更加灵活。
静态代理一般是一个真实主题类对应一个代理类,当抽象主题接口存在多个主题实现类时,对应的代理类也会逐渐增多。这时候如果想要一个代理类能代理多个实现类的话,
则需要使用动态代理进行处理。
2.动态代理
动态代理指的是代理类由程序在运行时动态生成,不用手动编写。
动态代理实现的几种方式:jdk动态代理、cglib动态代理
jdk动态代理
实现代码:
抽象主题接口类Subject和真实主题类RealSubject与聚合方式中的相同,不再复制。
/** * JDKDynamicProxy * jdkd动态代理 * * @author * @create 2018-03-29 16:17 **/ public class JDKDynamicProxy implements InvocationHandler { private Object target; public JDKDynamicProxy(Object target) { this.target = target; } public <T> T getProxy() { return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Do something before"); Object result = method.invoke(target, args); System.out.println("Do something after"); return result; } }
/** * Client * client测试代码 * @author * @create 2018-03-29 14:26 **/ public class Client { public static void main(String[] args) { // jdk动态代理测试 Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy(); subject.doSomething(); } }
jdk动态代理支持一个代理类可以代理多个主题实现类的问题,但是还有一个问题就是只能动态代理接口,而不能代理不是接口的类。
cglib动态代理
实现代码:
抽象主题接口类Subject和真实主题类RealSubject与聚合方式中的相同,不再复制。
此处选用spring框架中的cglib实现。
/** * Fish * 真实主题类 * @author * @create 2018-03-29 17:00 **/ public class Fish { public void swim() { System.out.println("Do you like swimming"); } }
/** * CGLibDynamicProxy * cglib动态代理 * @author * @create 2018-03-29 16:37 **/ public class CGLibDynamicProxy implements MethodInterceptor { private static CGLibDynamicProxy instance = new CGLibDynamicProxy(); public static CGLibDynamicProxy getInstance() { return instance; } public <T> T getProxy(Class<T> cls) { return (T) Enhancer.create(cls, this); } @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Do something before"); Object result = methodProxy.invokeSuper(target, args); System.out.println("Do something after"); return result; } }
/** * Client * client测试代码 * @author * @create 2018-03-29 14:26 **/ public class Client { public static void main(String[] args) { // cglib动态代理测试 Fish fish = CGLibDynamicProxy.getInstance().getProxy(Fish.class); fish.swim(); } }
cglib可以代理没有接口的类。