设计模式之代理模式

静态代理

静态代理的本质,就是通过特有方法对指定方法,在调用前后进行程序处理

1.定义发送短信的接口 public interface SmsService { String send(String message); } 2.实现发送短信的接口 public class SmsServiceImpl implements SmsService { public String send(String message) { System.out.println("send message:" + message); return message; } } 3.创建代理类并同样实现发送短信的接口 public class SmsProxy implements SmsService { private final SmsService smsService; public SmsProxy(SmsService smsService) { this.smsService = smsService; } @Override public String send(String message) { //调用方法之前,我们可以添加自己的操作 System.out.println("before method send()"); smsService.send(message); //调用方法之后,我们同样可以添加自己的操作 System.out.println("after method send()"); return null; } } 4.实际使用 public class Main { public static void main(String[] args) { SmsService smsService = new SmsServiceImpl(); SmsProxy smsProxy = new SmsProxy(smsService); smsProxy.send("java"); } } 运行上述代码之后,控制台打印出: before method send() send message:java after method send()

动态代理

动态代理分为 JDK动态代理 与 CGLib动态代理。相对于静态代理,动态代理更灵活。本质就是通过反射的方式创建代理对象。从JVM 角度讲,静态代理会生成一个指定的class文件,而动态代理是在运行时动态生成字节码,加载到JVM 中。JDK动态代理效率高,首选此方式代理。

JDK动态代理

注意点:

  1. CustomHandler 必须实现 InvocationHandler
  2. trageClass 必须实现接口
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象,CustomHandler 的invoke方法中自定义前后程序。
1.定义发送短信的接口 public interface SmsService { String send(String message); } 2.实现发送短信的接口 public class SmsServiceImpl implements SmsService { public String send(String message) { System.out.println("send message:" + message); return message; } } 3.定义一个 JDK 动态代理类 public class CustomHandler implements InvocationHandler { // 代理类中的真实对象 private final Object target; public DebugInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { //调用方法之前,我们可以添加自己的操作 System.out.println("before method " + method.getName()); Object result = method.invoke(target, args); //调用方法之后,我们同样可以添加自己的操作 System.out.println("after method " + method.getName()); return result; } } 4.获取代理对象的工厂类 public class JdkProxyFactory { public static Object getProxy(Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), // 目标类的类加载 target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个 new CustomHandler (target) // 代理对象对应的自定义 InvocationHandler ); } } 5.实际使用 SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); smsService.send("java"); 运行上述代码之后,控制台打印出: before method send send message:java after method send

CGLib 动态代理

注意点:

  1. trageClass 必须有父类
  2. CustomInterceptor 必须  MethodInterceptor,本质就是使用拦截器
  3. 通过 Enhancer的creator方法实现代理
  4. CGLib 是基于java的扩展功能,有自己的编译器
1.实现一个使用阿里云发送短信的类 package github.javaguide.dynamicProxy.cglibDynamicProxy; public class AliSmsService { public String send(String message) { System.out.println("send message:" + message); return message; } } 2.自定义 MethodInterceptor(方法拦截器) public class CustomInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //调用方法之前,我们可以添加自己的操作 System.out.println("before method " + method.getName()); Object object = methodProxy.invokeSuper(o, args); //调用方法之后,我们同样可以添加自己的操作 System.out.println("after method " + method.getName()); return object; } } 3.获取代理类 public class CglibProxyFactory { public static Object getProxy(Class<?> clazz) { // 创建动态代理增强类 Enhancer enhancer = new Enhancer(); // 设置类加载器 enhancer.setClassLoader(clazz.getClassLoader()); // 设置被代理类 enhancer.setSuperclass(clazz); // 设置方法拦截器 enhancer.setCallback(new CustomInterceptor()); // 创建代理类 return enhancer.create(); } } 4.实际使用 AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class); aliSmsService.send("java"); 运行上述代码之后,控制台打印出: before method send send message:java after method send

Spring 中动态代理

Spring AOP 的本质就是动态代理,以下代码:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 这段代码用来判断选择哪种创建代理对象的方式 // config.isOptimize() 是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false // config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false // hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型不是SpringProxy类型 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 上面的三个方法有一个为true的话,则进入到这里 // 从AdvisedSupport中获取目标类 类对象 Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } // 判断目标类是否是接口 如果目标类是接口的话,则还是使用JDK的方式生成代理对象 // 如果目标类是Proxy类型 则还是使用JDK的方式生成代理对象 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象 return new ObjenesisCglibAopProxy(config); } else { // 使用JDK的提供的代理方式生成代理对象 return new JdkDynamicAopProxy(config); } } private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { // 获取代理类型接口 Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }

__EOF__

本文作者之士咖啡
本文链接https://www.cnblogs.com/zz-1q/p/16126411.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   之士咖啡  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示