Spring AOP面向切面编程

news2024/11/17 8:16:41

AOP将通用的、与业务无关的功能抽象封装为切面类。
切面可配置在目标方法的执行前、后运行,真正做到即插即用。实现了在不修改源码的情况下对程序行为进行扩展。

Spring AOP与AspectJ的关系:

Eclipse AspectJ 是基于Java平台的面向切面编程的语言。
Spring AOP底层依赖AspectJWeaver实现类和方法的匹配。
Spring AOP利用代理模式实现对象运行时功能扩展。

关键:

在这里插入图片描述

利用XML配置AOP的过程:

  1. 依赖AspectJ
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  1. 实现切面类/方法
    在这里插入图片描述

  2. 配置Aspect Bean

<!--AOP配置-->
<bean id="methodAspect" class="spring.aop.aspect.MethodAspect">
  1. 定义PointCut
<!--PointCut 切点,使用execution表达式描述切面的作用范围-->
<!--execution(public * spring.aop..*.*(..)) 说明切面作用在spring.aop包下的所有类所有方法上-->
<aop:pointcut id="pointcut" expression="execution(public * spring.aop..*.*(..))"></aop:pointcut>
  1. 配置Advice
<!--定义切面类-->
<aop:aspect ref="methodAspect">
<!--before通知(advice),代表在目标方法运行前先执行methodAspect.printExecutionTime()-->
<aop:before method="printExecutionTime" pointcut-ref="pointcut"/>
</aop:aspect>

JoinPoint连接点参数的核心方法

在这里插入图片描述

在这里插入图片描述

PointCut 切点表达式

在这里插入图片描述

public可以去掉,默认调用public类型方法。

<!--        对类约束-->
        <aop:pointcut id="pointcut" expression="execution(* spring.aop..*Service.*(..))"></aop:pointcut>
<!--        对方法名约束-->
        <aop:pointcut id="pointcut1" expression="execution(* spring.aop..*.create*(..))"></aop:pointcut>
<!--        对方法返回值类型约束-->
        <aop:pointcut id="pointcut2" expression="execution(String spring.aop..*.*(..))"></aop:pointcut>
<!--        对方法参数约束-->
        <aop:pointcut id="pointcut3" expression="execution(* spring.aop..*.*(String,*))"></aop:pointcut>

Advice 五种通知类型

在这里插入图片描述

特殊通知:引介增强

引介增强是对类的增强,允许在运行时为目标类增加新属性或方法。允许在运行时改变类的行为,让类随运行环境动态变更。

//切面类
public class MethodAspect {

    public void doAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("<---返回后通知:"+ret);
    }
    public void doAfterThrowing(JoinPoint joinPoint,Throwable th){
        System.out.println("<---异常通知:"+th.getMessage());
    }
    public void doAfter(JoinPoint joinPoint){
        System.out.println("<---触发后置通知");
    }
}
<!--定义切面类-->
<aop:aspect ref="methodAspect">
    <aop:after method="doAfter" pointcut-ref="pointcut"/>
    <aop:after-returning method="doAfterReturning" returning="ret" pointcut-ref="pointcut"/>
    <aop:after-throwing method="doAfterThrowing" throwing="th" pointcut-ref="pointcut"/>
</aop:aspect>

返回后通知/异常通知 与 后置通知 的执行顺序由配置顺序决定。

环绕通知的方法返回值为Object,需要返回目标方法的返回值,方法参数为ProceedingJoinPoint。

利用环绕通知计算方法执行时长:

public class MethodChecker {
    //ProceedingJoinPoint 是JoinPoint的升级版,在原有功能外,还可以控制目标方法是否执行
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        try {
            long startTime = new Date().getTime();
            Object ret = pjp.proceed();//执行目标方法
            long endTime = new Date().getTime();
            long duration = endTime - startTime;
            if(duration >= 1000){
                String className = pjp.getTarget().getClass().getName();
                String methodName =pjp.getSignature().getName();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
                String now = sdf.format(new Date());
                System.out.println("==="+now+":"+className+"."+methodName+"("+duration+"ms)===");
            }
            return ret;
        } catch (Throwable e) {
            System.out.println("Exception message:"+e.getMessage());
            throw e;
        }
    }
}
<bean id="methodChecker" class="spring.aop.aspect.MethodChecker"></bean>
<aop:config>
      <aop:pointcut id="pointcut" expression="execution(* spring.aop..*.*(..))"/>
      <aop:aspect ref="methodChecker">
      		<!--环绕通知-->
       		<aop:around method="check" pointcut-ref="pointcut"/>
      </aop:aspect>
</aop:config>

利用注解配置Spring AOP

  1. 依赖AspectJ
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  1. 在applicationContext.xml中增加两行
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 组件扫描:在IOC容器初始化时,去扫描哪个包下的所有组件类型注解-->
    <context:component-scan base-package="spring.aop"/>
<!--启用Spring AOP注解模式-->
    <aop:aspectj-autoproxy/>
</beans>
  1. 在每个组件类上增加组件类型注解,说明当前类需要被IoC实例化
  2. 切面类需要使用两个个注解:@Component @Aspect
  3. 切面方法上使用对应类型的通知注解,并增加对应的切点表达式
@Component //标记当前类为组件
@Aspect //说明当前类是切面类
public class MethodChecker {
    //环绕通知,参数为PointCut切点表达式
    @Around("execution(* spring.aop..*Service.*(..))")
     public Object check(ProceedingJoinPoint pjp) throws Throwable {
     ...
     }
}

Spring AOP实现原理

基于代理模式实现功能动态扩展,包括两种形式:

  • 目标类实现了接口,通过JDK动态代理实现功能扩展
  • 目标类没实现接口,通过CGLib组件实现功能扩展

代理模式:

通过代理对象对原对象实现功能扩展。
在这里插入图片描述
代理类和委托类都实现了相同的接口,代理类持有委托类对象引用,在代理类的实现方法中对原始功能扩展。

弊端:每个委托类至少拥有一个代理类,随着功能的扩展,手动创建的代理类越来越多,导致系统臃肿。

这种需要手动创建代理类的代理模式使用方式称为 静态代理

JDK动态代理

在运行时通过反射技术,按照接口的结构自动生成相应代理类,完成目标方法的扩展。

**
 * InvocationHandlerJDK提供的反射类,用于JDK动态代理中对目标方法进行增强
 * InvocationHandler实现类与切面类对环绕通知类似
 */
public class ProxyInvocationHandler implements InvocationHandler{
    private Object target;//代理类持有目标类对象
    private ProxyInvocationHandler(Object target){//传入目标对象
        this.target=target;
    }
    /**
     * 在invoke()方法对目标方法进行增强
     * @param proxy 代理类对象
     * @param method 目标方法对象
     * @param args 目标方法实参
     * @return 目标方法运行后返回值
     * @throws Throwable 目标方法抛出的异常
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("======"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) +"=======");
        Object ret = method.invoke(target,args);//调用目标方法
        return ret;
    }
}
 public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
        //动态创建代理类
        UserService userServiceProxy =(UserService) Proxy.newProxyInstance //根据已有接口创建代理类
                (userService.getClass().getClassLoader(),//类加载器
                 userService.getClass().getInterfaces(),//类要实现的接口
                 invocationHandler);//如何对目标方法进行扩展

        userServiceProxy.createUser();
 }

在这里插入图片描述

JDK动态创建代理类,只有在目标类实现了接口的情况下才可以。

CGLib实现代理类

CGLib是运行时字节码增强技术。
Spring AOP扩展无接口类使用CGLib。
在运行时生成目标继承类字节码的方式进行扩展。

CGLib实现原理:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1299042.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DNSLog漏洞探测(二)之常用DNSLog平台

常用DNSLog平台 我们在上一篇文章中我们介绍了什么是DNSLog&#xff0c;如果我们自己要去搭建一个DNSLog的服务平台&#xff0c;还是比较复杂和麻烦的&#xff0c;所以我们可以直接去使用一些公开免费的DNSLog平台&#xff0c;DNSLog的平台非常的多&#xff0c;但是实际上大部…

Spring基于xml半注解开发

目录 Component的使用 依赖注解的使用 非自定义Bean的注解开发 Component的使用 基本Bean注解&#xff0c;主要是使用注解的方式替代原有的xml的<bean>标签及其标签属性的配置&#xff0c;使用Component注解替代<bean>标签中的id以及class属性&#xff0c;而对…

奥威亚教学视频应用云平台 VideoCover任意文件上传漏洞复现

0x01 产品简介 广州市奥威亚电子科技有限公司教学视频应用云平台是一个专门为教育机构和个人教师设计的在线学习平台。该平台提供丰富的教学资源和功能,旨在提升教学效果和学习体验。 0x02 漏洞概述 奥威亚教学视频应用云平台 VideoCover.aspx接口处存在任意文件上传漏洞,未…

2.postman环境变量及接口关联

一、环境变量以及全局变量 操作流程 1.点击environment 2.点击environment右侧号&#xff0c;新增环境变量 3.在变量中输入变量名以及变量值 4.回到collection页面&#xff0c;修改变量环境 5.在collection中通过{{变量名}}调用变量 变量定义 环境变量&#xff1a;环境变量…

Xilinx原语详解——IBUFDS OBUFDS

在使用FPGA时&#xff0c;往往会用到一些差分信号&#xff0c;比如HDMI接口&#xff0c;LVDS接口的ADC、显示器等等设备&#xff0c;而FPGA内部往往只会使用单端信号&#xff0c;就需要完成单端信号和差分信号的相互转换&#xff0c;xilinx提供了两个原语对所有IO信号实现差分和…

【基于ESP32无线蓝牙上传电脑Excel透传数据】

【基于ESP32无线蓝牙上传电脑透传数据】 1. 引言2. 环境搭建2.1 硬件准备:2.2 软件准备:2.3. 配置Excel端口接收功能3. 测试代码4. 连接电脑和 ESP324.1 烧录程序4.2 启动蓝牙服务4.3 测试数据透传5. 总结1. 引言 随着物联网技术的发展,越来越多的设备开始支持无线通信,其…

正在快速兴起的云数据架构

云数据架构的日益流行表明了一个主题&#xff1a;在未来几年&#xff0c;越来越多的企业将把他们的数据中心业务完全迁移到云平台上&#xff0c;因为内部部署数据中心设施具有一些固有的优势。数字时代的企业生存已经成为向云迁移的代名词。 云数据架构的日益流行表明了一个主…

Java:字节流 文件输出与读入方法 并 实现文件拷贝

文章目录 字节 流FileOutputStream换行 与 续写FileInputstream实现 文件拷贝&#xff08;字节数组 读入方法&#xff09;字节流 编码 字节 流 FileOutputStream 创建对象&#xff0c;指定位置&#xff08;产生数据传输通道&#xff09; 参数可以是File对象&#xff0c;也可以…

Python time模块详解

time 模块主要包含各种提供日期、时间功能的类和函数。该模块既提供了把日期、时间格式化为字符串的功能&#xff0c;也提供了从字符串恢复日期、时间的功能。 在 Python 的交互式解释器中先导入 time 模块&#xff0c;然后输入 [e for e in dir(time) if not e.startswith(_)…

最简单的基于 FFmpeg 的音频解码器

最简单的基于 FFmpeg 的音频解码器 最简单的基于 FFmpeg 的音频解码器正文参考工程文件下载 参考雷霄骅博士的文章&#xff0c;链接&#xff1a;最简单的基于FFMPEGSDL的音频播放器&#xff1a;拆分-解码器和播放器 最简单的基于 FFmpeg 的音频解码器 正文 FFmpeg 音频解码器…

c++新经典模板与泛型编程:标准库容器中元素类型的萃取

通过容器(数组)类型萃取元素类型 用GetEleType类模板进行常规实现 #include <iostream>#include <vector> #include <list>// 泛化版本 template<typename T> struct GetEleType;// 特化版本 template<typename T> struct GetEleType<std::v…

Elasticsearch:向量数据库的真相

通过工作示例了解什么是向量数据库、它们如何实现 “相似性” 搜索以及它们可以在明显的 LLM 空间之外的哪些地方使用。除非你一直生活在岩石下&#xff0c;否则你可能听说过诸如生成式人工智能和大型语言模型&#xff08;LLM&#xff09;之类的术语。 除此之外&#xff0c;你很…

Rellax.js,一款超酷的 JavaScript 滚动效果库

嗨&#xff0c;大家好&#xff0c;欢迎来到猿镇&#xff0c;我是镇长&#xff0c;lee。 又到了和大家见面的时间&#xff0c;今天和大家分享一款轻松实现视差滚动效果的 JavaScript 库——Rellax.js。无需大量的配置&#xff0c;即可为你的网站增色不少。 什么是Rellax.js&am…

Flutter自定义下拉选择框dropDownMenu

利用PopupMenuButton和PopupMenuItem写了个下拉选择框&#xff0c;之所以不采用系统的&#xff0c;是因为自定义的更能适配项目需求&#xff0c;话不多说&#xff0c;直接看效果 下面直接贴出代码、代码中注释写的都很清楚&#xff0c;使用起来应该很方便&#xff0c;如果有任何…

【完整项目】双模式答题卡识别软件中YOLO模式的训练部分详解,包括训练填涂区域和手写准考证号,手把手详细教学,可延申拓展训练其他图像数据

目录 前言1. 数据准备2. 数据标注3. 先跑起来Windows下用本地的CPU或GPU训练本地Windows系统连接服务器训练前言 前文:【完整项目】基于Python+Tkinter+OpenCV+Yolo+手写OCR的双模式答题卡识别软件的设计与实现 如果你需要训练自己的答题卡模型,那么请先看上面的文章链接。…

uniapp自定义的日历(纯手写)

效果图&#xff1a; html&#xff1a; <!-- 年月 --><view class"box"><view class"box_time"><view class"time"><image click"lefts" :src"url/uploads/20231206/9d1fb520b12383960dca3c214d84fa0…

uniapp图片预览

用的是Uview组件库里面的 直接在页面写上&#xff1a; <u-album singleSize"100" :urls"[https://lxt.jingyi.icu/item.img]"></u-album> 这图片路径是我自己的 你们可以按照组件库里面的方法去实现

掌握JavaScript继承的精髓:原型继承、构造函数继承以及组合继承的实现技巧

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;JavaScript篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript-Javascript如何实现继承&#xff1f; 目录 一、是什么 二、实现方式 …

智能优化算法应用:基于蜉蝣算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蜉蝣算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蜉蝣算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蜉蝣算法4.实验参数设定5.算法结果6.参考文献7.MA…

侮辱性涨薪!业绩得了S,调薪涨了450

信安这个行业3年前各大媒体&#xff0c;信安自己人都觉得自己在个朝阳行业&#xff0c;红利在咋弄不得再吃5年。 现在拉个干网络安全的再去问问&#xff0c;看看谁不是去年年终奖砍了一半、或者根本就没了&#xff0c;再或者每天岌岌可危生怕去领大礼包。 原本10月份的激励性…