spring AOP之代理

news/2024/11/28 10:32:11/

1.代理概念

  • 什么是代理
    • 为某一个对象创建一个代理对象,程序不直接用原本的对象,而是由创建的代理对象来控制原对象,通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好的隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间
  • 什么是静态代理
    • 由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件就已经存在
  • 什么是动态代理
    • 在程序运行时,运用反射机制动态创建而成,无需手动编写代码
      • JDK动态代理
      • CGLib动态代理

2.静态代理

  • 什么是静态代理

    • 由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件就已经存在
    • 通过将目标类与代理类实现同一个接口,让代理类持有真实类对象,然后在代理类方法中调用真实类方法,在调用真实类方法的前后添加我们所需要的功能扩展代码来达到增强的目的
  • 优点

    • 代理使客户端不需要知道实现类是什么怎么做的,而客户端只需知道代理即可
    • 方便增加功能、扩展业务逻辑
  • 缺点

    • 代理类中出现大量冗余的代码,非常不利于扩展和维护
    • 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法,增加了代码维护的复杂度
  • 代码示例

    package com.gen;interface PayService {void pay();
    }class AliPayService implements PayService {@Overridepublic void pay() {System.out.println("支付宝支付");}
    }class StaticProxyPayService implements PayService {private PayService payService;public StaticProxyPayService(PayService payService) {this.payService = payService;}@Overridepublic void pay() {System.out.println("代理代码begin");this.payService.pay();System.out.println("代理代码end");}
    }public class Main {public static void main(String[] args) {new StaticProxyPayService(new AliPayService()).pay();}
    }
    

3.JDK动态代理

  • JDK动态代理与静态代理一样,目标类需要实现一个代理接口,再通过代理对象调用目标方法

  • 编写流程

    定义一个java.lang.reflect.InvocationHandler接口的实现类,重写invoke方法public interface InvocationHandler {/*** @param proxy  被代理的对象* @param method 要调用的方法* @param args   方法调用时所需参数*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }
    
  • 代码示例

    package com.gen;import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;interface PayService {void pay();
    }class AliPayService implements PayService {@Overridepublic void pay() {System.out.println("支付宝支付");}
    }class JdkProxy implements InvocationHandler {/*** 目标对象*/private Object targetObj;/*** 获取代理对象** @param targetObj* @return*/public Object newProxyInstance(Object targetObj) {this.targetObj = targetObj;// 绑定关系,也就是和具体的哪个实现类关联return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try {System.out.println("JDK代理代码begin");result = method.invoke(targetObj, args);System.out.println("JDK代理代码end");} catch (Exception e) {e.printStackTrace();}return result;}
    }public class Main {public static void main(String[] args) {PayService payService = (PayService) new JdkProxy().newProxyInstance(new AliPayService());payService.pay();}
    }
    

4.CGLib动态代理

  • CGLib动态代理的原理是对指定的业务类生成一个子类,并覆盖其中的业务方法来实现代理

  • 代码示例

    package com.gen;import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;interface PayService {void pay();
    }class AliPayService implements PayService {@Overridepublic void pay() {System.out.println("支付宝支付");}
    }class CglibProxy implements MethodInterceptor {/*** 目标对象*/private Object targetObj;/*** 获取代理对象** @param targetObj* @return*/public Object newProxyInstance(Object targetObj) {this.targetObj = targetObj;Enhancer enhancer = new Enhancer();// 设置代理类的父类enhancer.setSuperclass(this.targetObj.getClass());// 设置回调函数enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object result = null;try {System.out.println("CGLib代理代码begin");result = methodProxy.invokeSuper(o, args);System.out.println("CGLib代理代码end");} catch (Exception e) {e.printStackTrace();}return result;}
    }public class Main {public static void main(String[] args) {PayService payService = (PayService) new CglibProxy().newProxyInstance(new AliPayService());payService.pay();}
    }
    

5.总结

  • 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理,解耦和易维护

  • 两种动态代理的区别

    • JDK动态代理:要求目标对象实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以用CGLib动态代理
    • CGLib动态代理它是在内存中构建一个子类对象,从而实现对目标对象功能的扩展
    • JDK动态代理是自带的,CGLib需要引入第三方包
    • CGLib动态代理基于继承来实现代理,所以无法对final类、private方法和static方法实现代理
  • spring AOP中的代理使用的默认策略

    • 如果目标对象实现了接口,则默认采用JDK动态代理
    • 如果目标对象没有实现接口,则采用CGLib动态代理
    • 如果目标对象实现了接口,程序里面依旧可以指定使用CGLib动态代理

http://www.ppmy.cn/news/1078761.html

相关文章

IBM安全发布《2023年数据泄露成本报告》,数据泄露成本创新高

近日,IBM安全发布了《2023年数据泄露成本报告》,该报告针对全球553个组织所经历的数据泄露事件进行深入分析研究,探讨数据泄露的根本原因,以及能够减少数据泄露的技术手段。 根据报告显示,2023年数据泄露的全球平均成…

ransac拟合平面,代替open3d的segment_plane

0.open3d打包太大了,所以决定网上找找代码 使用open3d拟合平面并且求平面的法向量,open3d打包大概1个g的大小。 import open3d as o3dpcd o3d.geometry.PointCloud()pcd.points o3d.utility.Vector3dVector(points)## 使用RANSAC算法拟合平面plane_m…

【ES6】Promise.race的用法

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。 const p Promise.race([p1, p2, p3]);上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值&#…

union all 和 union 的区别,mysql union全连接查询

602. 好友申请 II :谁有最多的好友(力扣mysql题,难度:中等) RequestAccepted 表: ------------------------- | Column Name | Type | ------------------------- | requester_id | int | | accepter_id | int | | accept_date …

新款奥迪 A7L 正式上市,媒介盒子多家媒体助阵

新款奥迪 A7L 正式上市,媒介盒子多家媒体助阵! 哈喽,大家好,今天媒介盒子小编又来跟大家分享媒体推广的干货知识了,本篇分享的主要内容是:新车上市,上汽奥迪A7L的营销策略。 新款奥迪 A7L 正式上市,新车推出 11 款车型,售价为 4…

唯一索引比普通索引快吗?运行原理是什么?

推荐阅读 项目实战:AI文本 OCR识别最佳实践 AI Gamma一键生成PPT工具直达链接 玩转cloud Studio 在线编码神器 玩转 GPU AI绘画、AI讲话、翻译,GPU点亮AI想象空间 资源分享 史上最全文档AI绘画stablediffusion资料分享 AI绘画关于SD,MJ,GPT,SDXL百科全书 AI绘画 stable…

论文阅读》用提示和释义模拟对话情绪识别的思维过程 IJCAI 2023

《论文阅读》用提示和复述模拟对话情绪识别的思维过程 IJCAI 2023 前言简介相关知识prompt engineeringparaphrasing模型架构第一阶段第二阶段History-oriented promptExperience-oriented Prompt ConstructionLabel Paraphrasing损失函数前言 你是否也对于理解论文存在困惑?…

Linux拓展之阻止或禁用普通用户登录

禁止指定用户登录 chsh -s /sbin/nologin 指定用户名示例 chsh -s /sbin/nologin testuser恢复指定用户登录 chsh -s /bin/bash 指定用户名示例 chsh -s /bin/bash testuser参考 https://blog.csdn.net/cnds123321/article/details/125232580 https://www.cnblogs.com/cai…