代理模式
Java代理模式
简单来说,就是给原本的类书写一个代理类,我们通过代理类来操作原类。可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
一、静态代理
静态代理中,我们对目标对象的每个方法的增强都是手动完成的,非常不灵活且麻烦。具体步骤:
定义一个接口及其实现类;
创建一个代理类同样实现这个接口
将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。
1、创建一个接口
public interface SmsService { String send(String msg); }
2、定义一个实现类(这就是我们被代理的对象)
public class SmsServiceImpl implements SmsService { @Override public String send(String msg) { System.out.println("我发送了消息:" + msg); return msg; } }
3、定义一个代理类
其实这里我们可以思考一下,代理类由于和原本类实现了同一个接口,所以原类必须实现的规则代理类也必须实现。而且在此基础上由于维护了一个原类的对象的接口属性,可以通过有参构造方法传递需要代理的类并进行补充和增强。
public class SmsProxy implements SmsService { private final SmsService smsService; // 维护一个常量对象 public SmsProxy(SmsService smsService) { //类初始化的时候赋值 this.smsService = smsService; } @Override public String send(String msg) { System.out.println("在发送之前"); String m = this.smsService.send(msg); System.out.println("在发送之后"); return m; } }
4、测试
public class Main { public static void main(String[] args) { SmsService smsService = new SmsServiceImpl(); SmsProxy smsProxy = new SmsProxy(smsService); smsProxy.send("你好世界!"); } }
对应的输出结果(这里其实感觉到了一点Spring AOP的影子了是吧):
在发送之前 我发送了消息:你好世界! 在发送之后
二、动态代理
JDK动态代理机制
流程:
定义一个接口及其实现类;
自定义 InvocationHandler
并重写invoke
方法,在 invoke
方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象;
1、创建一个接口
public interface SmsService { String send(String message); }
2、定义一个实现类
public class SmsServiceImpl implements SmsService { @Override public String send(String message) { System.out.println("发送了消息:" + message); return message; } }
3、定义一个 InvocationHandler 的实现类并重写 invoke 方法,没有自己针对每一个需要代理的类都写一个代理类
这里可以想一下,我们可以对一些方法进行增强,当然也可以通过判断一些特殊的方法进行一定的特殊处理。
public class DebugInvocationHandler implements InvocationHandler { /** * 代理类中的真实对象 */ private final Object target; public DebugInvocationHandler(Object target) { this.target = target; } /** * 反射的感觉 * invoke() 方法: 当我们的动态代理对象调用原生方法的时候, * 最终实际上调用到的是 invoke() 方法, * 然后 invoke() 方法代替我们去调用了被代理对象的原生方法 * @param proxy 动态生成的代理类 * @param method 与代理类对象调用的方法相对应 * @param args 当前 method 方法的参数 * @return * @throws InvocationTargetException * @throws IllegalAccessException */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { //调用方法之前,我们可以添加自己的操作 System.out.println("在方法调用之前"); Object result = method.invoke(target, args); //调用方法之后,我们同样可以添加自己的操作 System.out.println("在方法调用之后"); return result; } }
4、定义简单工厂类获取代理对象
这里的Proxy类的 newProxyInstance 方法用于生成一个代理类的实例,然后会去调用传入的自定义的 InvocationHandler 的实现类中的 invoke 方法。
public class JdkProxyFactory { /** 传入的参数是被代理的对象,返回的是其代理对象 */ public static Object getProxy(Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), // 目标类的类加载器,可以去了解一下JVM类加载过程 target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个 new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler ); } }
5、测试
public class Main { public static void main(String[] args) { SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); smsService.send("java"); } }
对应输出结果:
在方法调用之前 发送了消息:java 在方法调用之后
CGLIB 动态代理机制
关键在于,这个方式不需要被代理的类实现某一个接口。
流程:
定义一个类;
自定义 MethodInterceptor
并重写 intercept
方法,intercept
用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke
方法类似;
通过 Enhancer
类的 create()
创建代理类;
1、创建一个maven项目
引入依赖:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
2、定义一个类
public class SmsService { public String send(String msg) { System.out.println("发送消息:" + msg); return msg; } }
3、定义一个 MethodInterceptor 的实现类 并重写其中的 intercept 方法
public class DebugMethodInterceptor implements MethodInterceptor { /** * @param o 被代理的对象(需要增强的对象) * @param method 被拦截的方法(需要增强的方法) * @param args 方法入参 * @param methodProxy 用于调用原始方法 */ @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //调用方法之前,我们可以添加自己的操作 System.out.println("在方法调用之前"); Object object = methodProxy.invokeSuper(o, args); //调用方法之后,我们同样可以添加自己的操作 System.out.println("在方法调用之后"); return object; } }
4、定义简单工厂类获取代理对象
这里的Enhancer类的 create() 方法用于生成一个代理类的实例,使用前设置对应的几个参数。
public class CglibProxyFactory { public static Object getProxy(Class<?> clazz) { // 创建动态代理增强类 Enhancer enhancer = new Enhancer(); // 设置类加载器 enhancer.setClassLoader(clazz.getClassLoader()); // 设置被代理类 enhancer.setSuperclass(clazz); // 设置方法拦截器,这里是你自实现的拦截器 enhancer.setCallback(new DebugMethodInterceptor()); // 创建代理类 return enhancer.create(); } }
5、测试
public class Main { public static void main(String[] args) { SmsService aliSmsService = (SmsService) CglibProxyFactory.getProxy(SmsService.class); aliSmsService.send("你好世界!"); } }
对应输出结果:
在方法调用之前 发送消息:你好世界! 在方法调用之后
本文作者:如此而已~~~
本文链接:https://www.cnblogs.com/fragmentary/p/18276962
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步