代理模式是一种非常好理解的设计模式,生活中处处可见代理:张三作为一个明星,不可能什么事都由他自己干,于是他请了经纪人;张三 LOL 水平不够,又想上分怎么办,请游戏代练;张三逃税被抓怎么办,请律师帮忙打官司。无论是经纪人、游戏代练或是律师,他们都是帮张三干活,但又不能一手包办 ,只能帮张三处理一些他不愿干或干不了的事情。
代理模式 代理模式(Proxy Pattern)是通过代理对象来访问目标对象,可以在实现目标对象功能的基础上,增加额外的操作,达到扩展目标对象功能的目的。
类结构图
静态代理 定义 静态代理是定义接口或者父类,然后被代理对象(RealSubject)与代理对象(Proxy)一起实现相同的接口或继承相同的父类。
示例 1 2 3 public interface Subject { void action(); }
1 2 3 4 5 6 public class RealSubject implements Subject{ @Override public void action() { System.out.println("RealSubject do action."); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Proxy implements Subject { private Subject target; public Proxy(Subject target) { this.target = target; } @Override public void action() { System.out.println("do something before."); target.action(); System.out.println("do something after."); } }
1 2 3 4 5 6 7 8 9 10 public class Client { public static void main(String[] args) { //1.创建被代理对象 Subject target = new RealSubject(); //2.创建代理对象, 同时将被代理对象传递给代理对象 Proxy proxy = new Proxy(target); //3.通过代理对象,调用到被代理对象的方法 proxy.action(); } }
运行结果
JDK 动态代理 定义 JDK 代理的目标对象必须要实现接口,而代理对象则是在内存中动态生成的。
JDK 代理使用 java.lang.reflect.Proxy 中的 newProxyInstance 方法来创建代理对象,该方法需要如下三个参数:
ClassLoader loader
Class<?>[] interfaces
InvocationHandler h
JDK 动态代理类图
示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class JDKProxy { //被代理对象。 private Object target; public JDKProxy(Object target) { this.target = target; } //利用 JDK api 动态生成一个代理对象。 public Object getProxyInstance() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK 动态代理开始"); //反射机制调用目标对象的方法 Object returnVal = method.invoke(target, args); System.out.println("JDK 动态代理结束"); return returnVal; } }); } }
1 2 3 4 5 6 7 8 9 10 11 12 public class Client { public static void main(String[] args) { //1.创建目标对象 RealSubject target = new RealSubject(); //2.创建代理对象 Subject proxyInstance = (Subject) new JDKProxy(target).getProxyInstance(); //3.打印内存中动态生的代理对象 System.out.println(proxyInstance.getClass()); //4.通过代理对象,调用目标对象的方法 proxyInstance.action(); } }
运行结果
cglib 动态代理 定义 cglib(Code Generation Library) 代理的目标对象不需要实现接口,它是在内存中构建一个子类对象,从而实现对目标对象的代理。
cglib 是一个高性能的代码生成包,它可以在运行期扩展 java 类与实现 java 接口。被许多的 AOP 框架使用(如 Spring AOP)。cglib 包的底层是使用字节码处理框架 ASM 来生成新的类。
cglib 代理的类不能为 final,否则会报 java.lang.IllegalArgumentException 异常,这是因为 final 修饰的类不能被继承。 如果目标对象的方法为 final 或 static,那么也不会被拦截(只会执行目标对象的方法,不会执行代理逻辑)。
cglib 动态代理类图
代理对象需要实现 MethodInterceptor 接口中的 intercept() 方法。
示例 下载 jar 包
将 jar 包添加到项目中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class CglibProxy implements MethodInterceptor { //目标对象 private Object target; public CglibProxy(Object target) { this.target = target; } //返回target对象的代理对象 public Object getProxyInstance() { //创建一个工具类 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(target.getClass()); //设置回调函数 enhancer.setCallback(this); //创建子类对象,即代理对象 return enhancer.create(); } //重写intercept方法,会调用目标对象的方法 @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("cglib 动态代理开始"); Object returnVal = method.invoke(target, args); System.out.println("cglib 动态代理结束"); return returnVal; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Client { public static void main(String[] args) { //1.创建目标对象 RealSubject target = new RealSubject(); //2.获取到代理对象,并且将目标对象传递给代理对象 Subject proxyInstance = (Subject) new CglibProxy(target).getProxyInstance(); //3.打印内存中动态生的代理对象 System.out.println(proxyInstance.getClass()); //4.执行代理对象的方法,触发 intercept 方法,从而实现对目标对象的调用 proxyInstance.action(); } }
运行结果
小结 静态代理
优点:简单。
缺点:每一个目标对象都需要一个代理对象,所以会产生很多的代理类。一旦接口中新增方法,目标对象与代理对象都需要维护,十分繁琐。
JDK 动态代理
优点:不需要为每一个目标对象写一个代理类。
缺点:目标对象必须要实现接口才能代理。
cglib 动态代理
优点:因为是基于继承来实现的代理,目标对象没有实现接口也能代理。
缺点:不能代理 final 修饰的类和方法,因为 final 修饰的类不能被继承。
拓展 为什么 JDK 动态代理只能代理实现了接口的类? 因为 JDK 生成的代理类已经继承了 java.lang.reflect.Proxy 类,而 Java 只支持单继承,所以只能通过接口来实现代理。
改造 JDKProxy 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class JDKProxy { //被代理对象。 private Object target; public JDKProxy(Object target) { this.target = target; } //利用 JDK api 动态生成一个代理对象。 public Object getProxyInstance() { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //生成的代理类已经继承了 java.lang.reflect.Proxy 类。 System.out.println("proxy instanceof Proxy: " + (proxy instanceof Proxy)); //将生成的代理类输入到 JDKProxy.class 文件中,再通过 IDEA 反编译 JDKProxy.class 文件。 byte[] bytes = ProxyGenerator.generateProxyClass("proxy", target.getClass().getInterfaces()); File file = new File("./JDKProxy.class"); try { OutputStream outputStream = new FileOutputStream(file); outputStream.write(bytes); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } System.out.println("JDK 动态代理开始"); Object returnVal = method.invoke(target, args); System.out.println("JDK 动态代理结束"); return returnVal; } }); } }
运行结果
JDKProxy.class
查看 cglib 生成的代理类 改造 CglibProxy 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class CglibProxy implements MethodInterceptor { //目标对象 private Object target; public CglibProxy(Object target) { this.target = target; } //返回target对象的代理对象 public Object getProxyInstance() { //创建一个工具类 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(target.getClass()); //设置回调函数 enhancer.setCallback(this); //创建子类对象,即代理对象 return enhancer.create(); } //重写intercept方法,会调用目标对象的方法 @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //生成的代理类已经继承了 RealSubject 类。 System.out.println("proxy instanceof RealSubject: " + (proxy instanceof RealSubject)); System.out.println("cglib 动态代理开始"); Object returnVal = method.invoke(target, args); System.out.println("cglib 动态代理结束"); return returnVal; } }
改造 Client 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Client { public static void main(String[] args) { //0.将生成的代理类输入到 cglib 目录中。 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./cglib"); //1.创建目标对象 RealSubject target = new RealSubject(); //2.获取到代理对象,并且将目标对象传递给代理对象 RealSubject proxyInstance = (RealSubject) new CglibProxy(target).getProxyInstance(); //3.打印内存中动态生的代理对象 System.out.println(proxyInstance.getClass()); //4.执行代理对象的方法,触发 intercept 方法,从而实现对目标对象的调用 proxyInstance.action(); } }
运行结果
CglibProxy.class
引用