Spring AOP的应用

news2024/9/21 22:23:13

目录

1、maven坐标配置与xml头配置

2、代理方式的选择与配置

3、AOP的三种配置方式

3.1、XML模式

3.1.1 创建目标类和方法

3.1.2 创建切面

3.1.3 切面xml配置与表达式说明

3.1.4 单测

3.2 纯注解模式

3.2.1 开启注解相关配置

3.2.2 创建目标类和方法

3.2.3 创建切面并配置切面

3.2.4 单测

3.3 XML+注解模式

3.3.1 与纯注解模式配置的区别

3.3.2 单测


AOP本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、⽇志代码、事务控制代码、性能监控代码。

AOP的实现,主要靠动态代理技术,在运行期对需要使用的业务逻辑方法进行增强。

1、maven坐标配置与xml头配置

<!-- Spring AOP核心包 -->

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-aop</artifactId>

    <version>5.1.12.RELEASE</version>

</dependency>

<!-- Spring AOP注解配置包 -->

<dependency>

    <groupId>org.aspectj</groupId>

    <artifactId>aspectjweaver</artifactId>

    <version>1.9.4</version>

</dependency>



<!--junit 单元测试依赖 -->

<dependency>

    <groupId>junit</groupId>

    <artifactId>junit</artifactId>

    <version>4.13.2</version>

    <scope>test</scope>

</dependency>

Spring基于XML的AOP配置前准备

在已经配置了ioc的xml文件上进行添加   bean.xml

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

            http://www.springframework.org/schema/beans/spring-beans.xsd

            http://www.springframework.org/schema/aop

            https://www.springframework.org/schema/aop/spring-aop.xsd">

2、代理方式的选择与配置

Spring 实现AOP思想使⽤的是动态代理技术。

默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。

当被代理对象没有实现任何接⼝时,Spring会选择CGLIB。

当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术。

⽆论被代理对象是否实现接⼝,只要不是final修饰的类都可以采⽤cglib提供的⽅式创建代理对象。不过我们可以通过配置的⽅式,让Spring强制使⽤CGLIB。配置方式有以下两种

  • 使⽤aop:config标签配置

<aop:config proxy-target-class="true">
  • 使⽤aop:aspectj-autoproxy标签配置

<!--此标签是基于XML和注解组合配置AOP时的必备标签,表示Spring开启注解配置AOP的⽀持-->

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

3、AOP的三种配置方式

Spring的AOP和IOC一样,支持三类配置方式:

第⼀类:使⽤XML配置

第⼆类:使⽤纯注解配置

第三类:使⽤XML+注解组合配置

3.1、XML模式

3.1.1 创建目标类和方法

public class TargetObject{

    public void printLog(String content) {

        System.out.println("printLog打印目标内容:" + content);

    }

}

3.1.2 创建切面

切面是指增强的代码,增强的代码类,就是切面类。比如:事务切面类,里面定义的方法就是事务相关的,像开启事务,提交事务,回滚事务等等。

public class LogUtil {



    public void beforeLog() {

        System.out.println("AOP切面前置通知打印");

    }



    public void afterLog() {

        System.out.println("AOP切面后置通知打印");

    }



    public void afterReturnLog() {

        System.out.println("AOP切面返回值通知打印");

    }



    public void afterThrowLog() {

        System.out.println("AOP切面异常通知打印");

    }



    public void aroundLog() {

        System.out.println("AOP切面环绕通知打印");

    }

}

3.1.3 切面xml配置与表达式说明

bean.xml

<!-- 将相关Bean注入IOC容器-->

<bean id="logUtil" class="com.test.LogUtil"/>

<bean id="targetObject" class="com.test.TargetObject"/>



<!-- 声明AOP配置 -->

<aop:config>

    <!-- 配置切入点表达式 -->

    <aop:pointcut id="cutPrintLog" expression="execution(public * com.test.TargetObject.printLog(java.lang.String))"/>

    <!-- 配置切面 -->

    <aop:aspect id="aoplog" ref="logUtil">

        <!-- 配置前置通知 -->

        <aop:before method="beforeLog" pointcut-ref="cutPrintLog"/>

        <!-- 配置后置通知 -->

        <aop:after method="afterLog" pointcut-ref="cutPrintLog"/>

        <!-- 配置返回值通知 -->

        <aop:after-returning method="afterReturnLog" pointcut-ref="cutPrintLog"/>

        <!-- 配置异常通知 -->

        <!--<aop:after-throwing method="afterThrowLog" pointcut-ref="cutPrintLog"/>-->

        <!-- 配置前置通知 -->

        <!--<aop:around method="aroundLog" pointcut-ref="cutPrintLog"/>-->

    </aop:aspect>

</aop:config>

属性说明:

method:⽤于指定通知的⽅法名称

pointcut:⽤于指定切⼊点表达式

pointcut-ref:⽤于指定切⼊点表达式的引⽤

切入点表达式使用示例

全限定⽅法名 访问修饰符 返回值 包名.包名.包名.类名.⽅法名(参数列表)

全匹配⽅式:

public void com.test.TargetObject.printLog(java.lang.String)

访问修饰符可以省略

void com.test.TargetObject.printLog(java.lang.String)

返回值可以使⽤*,表示任意返回值

* com.test.TargetObject.printLog(java.lang.String)

包名可以使⽤.表示任意包,但是有⼏级包,必须写⼏个

* ....TargetObject.printLog(java.lang.String)

包名可以使⽤..表示当前包及其⼦包

* ..TargetObject.printLog(java.lang.String)

类名和⽅法名,都可以使⽤.表示任意类,任意⽅法

* ...(java.lang.String)



参数列表,可以使⽤具体类型

基本类型直接写类型名称 : int

引⽤类型必须写全限定类名:java.lang.String

参数列表可以使⽤*,表示任意参数类型,但是必须有参数

* *..*.*(*)

参数列表可以使⽤..,表示有⽆参数均可。有参数可以是任意类型

* *..*.*(..)



全通配⽅式:

* *..*.*(..)

3.1.4 单测

@Test

public void test01() {

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

    TargetObject target = (TargetObject) context.getBean("targetObject");

    target.printLog("aaa");

}

打印结果:

AOP切面前置通知打印

printLog打印目标内容:aaa

AOP切面后置通知打印

AOP切面返回值通知打印

3.2 纯注解模式

3.2.1 开启注解相关配置

@Configuration

@ComponentScan("com.test")

// 开启注解支持

@EnableAspectJAutoProxy

public class LoggingConfig {

}

3.2.2 创建目标类和方法

@Component("targetObject")

public class TargetObject{

    public void printLog(String content) {

        System.out.println("printLog打印目标内容:" + content);

    }

}

3.2.3 创建切面并配置切面

@Component

@Aspect

public class LogUtil {



    @Pointcut("execution(* com.test.TargetObject.printLog(..))")

    public void pointcut(){}



    @Before("pointcut()")

    public void beforePrintLog(JoinPoint jp){

        Object[] args = jp.getArgs();

        System.out.println("前置通知:beforePrintLog,参数是:"+

                Arrays.toString(args));

    }

    @AfterReturning(value = "pointcut()",returning = "rtValue")

    public void afterReturningPrintLog(Object rtValue){

        System.out.println("后置通知:afterReturningPrintLog,返回值 是:"+rtValue);

    }

    @AfterThrowing(value = "pointcut()",throwing = "e")

    public void afterThrowingPrintLog(Throwable e){

        System.out.println("异常通知:afterThrowingPrintLog,异常是:"+e);

    }

    @After("pointcut()")

    public void afterPrintLog(){

        System.out.println("最终通知:afterPrintLog");

    }

    /**

     * 环绕通知

     * @param pjp

     * @return

     */

    @Around("pointcut()")

    public Object aroundPrintLog(ProceedingJoinPoint pjp){

        //定义返回值

        Object rtValue = null;

        try{

            //前置通知

            System.out.println("前置通知");

            //1.获取参数

            Object[] args = pjp.getArgs();

            //2.执⾏切⼊点⽅法

            rtValue = pjp.proceed(args);

            //后置通知

            System.out.println("后置通知");

        }catch (Throwable t){

            //异常通知

            System.out.println("异常通知");

            t.printStackTrace();

        }finally {

            //最终通知

            System.out.println("最终通知");

        }

        return rtValue;

    }

}

3.2.4 单测

@Test

public void test02() {

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LoggingConfig.class);

    TargetObject target = (TargetObject) context.getBean("targetObject");

    target.printLog("aaa");

}

打印结果:

前置通知

前置通知:beforePrintLog,参数是:[aaa]

printLog打印目标内容:aaa

后置通知

最终通知

最终通知:afterPrintLog

后置通知:afterReturningPrintLog,返回值 是:null

3.3 XML+注解模式

3.3.1 与纯注解模式配置的区别

将 3.2.1 的LoggingConfig去掉,用xml配置;

将 3.2.2 和 3.2.3 的 @Component 去掉,用xml注入

<!-- XML中开启Spring对注解AOP的⽀持 -->
<aop:aspectj-autoproxy/>



<bean id="logUtil" class="com.test.LogUtil"/>

<bean id="targetObject" class="com.test.TargetObject"/>

3.3.2 单测

@Test

public void test01() {

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

    TargetObject target = (TargetObject) context.getBean("targetObject");

    target.printLog("aaa");

}

打印结果:

前置通知

前置通知:beforePrintLog,参数是:[aaa]

printLog打印目标内容:aaa

后置通知

最终通知

最终通知:afterPrintLog

后置通知:afterReturningPrintLog,返回值 是:null

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

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

相关文章

ChatGPT 4o 使用指南 (9月更新)

首先基础知识还是要介绍得~ 一、模型知识&#xff1a; GPT-4o&#xff1a;最新的版本模型&#xff0c;支持视觉等多模态&#xff0c;OpenAI 文档中已经更新了 GPT-4o 的介绍&#xff1a;128k 上下文&#xff0c;训练截止 2023 年 10 月&#xff08;作为对比&#xff0c;GPT-4…

java之斗地主部分功能的实现

今天我们要实现斗地主中发牌和洗牌这两个功能&#xff0c;该如何去实现呢&#xff1f; 1.创建牌类&#xff1a;52张牌每一张牌包含两个属性:牌的大小和牌的花色。 故我们优先创建一个牌的类(Card)&#xff1a;包含大小和花色。 public class Card { //单张牌的大小及类型/…

20240921在友善之臂的NanoPC-T6开发板上使用Rockchip原厂的Android12适配宸芯的数传模块CX6602N

127|console:/ # uname -a console:/ # ifconfig console:/ # ifconfig -a console:/ # ifconfig -a 130|console:/ # ifconfig usb0 192.168.42.130 console:/ # console:/ # ifconfig console:/ # iperf3 -s & iperf3 -c 192.168.42.130 -i 1 -t 30 20240921在友善之臂的…

828华为云征文|华为云Flexus云服务器X实例之openEuler系统下部署Grav内容管理系统

828华为云征文&#xff5c;华为云Flexus云服务器X实例之openEuler系统下部署Grav内容管理系统 前言一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、Grav介绍2.1 CMS介绍2.2 Grav简介2.3 Grav特点2.4 …

TinyML-On-The-Fly: 实时、低功耗、低成本的微控制器嵌入式设备内计算机视觉技术用于无人机图像分类

这篇论文的标题是《TinyML-On-The-Fly: Real-Time Low-Power and Low-Cost MCU-Embedded On-Device Computer Vision for Aerial Image Classification》&#xff0c;作者是 Riya Samanta, Bidyut Saha, Soumya K. Ghosh&#xff0c;来自印度理工学院克勒格布尔分校。论文主要研…

电子元器件之MOS管,附上几个常用MOS管电路和仿真。

MOS管是一种常用的电子元器件。 1.MOS管的类别 MOSFET简称MOS&#xff0c;是一种绝缘栅型场效应管。按照类别可以分为增强型mos管和耗尽型mos管。 导电沟道的形成方式‌ 增强型MOS管&#xff1a;在没有外加电压时&#xff0c;源极和漏极之间没有导电沟道存在。只有当栅极电…

【玉米田】

题目 代码 #include <bits/stdc.h> using namespace std; typedef long long LL;const int mod 1e8; const int M 1 << 12; LL f[13][M]; int g[13]; vector<int> state; vector<int> p[M]; int n, m; bool check(int x) {return !(x & x <&…

攻防世界---->Windows_Reverse1(补)

做题笔记。 做题回顾。 假设&#xff0c;我们不知道地址随机怎么办&#xff1f;不能动调&#xff0c;只能静态分析。 下载 查壳 upx脱壳。 32ida打开。 动调报错。 重新打开&#xff0c;静态分析。 跟进关键函数。 不明白可以反汇编和汇编一起看。 溯源。 *decode 取值等于 by…

分布式锁之 防误删(优化之UUID防误删)

文章目录 1、AlbumInfoApiController --》testLock()2、AlbumInfoServiceImpl --》testLock()3、问题&#xff1a;删除操作缺乏原子性。 实现如下&#xff1a; 1、AlbumInfoApiController --》testLock() Tag(name "专辑管理") RestController RequestMapping(&quo…

【计网】从零开始掌握序列化与反序列化 --- 基础知识储备与程序重构

从零开始掌握序列化与反序列化 1 初识序列化与反序列化2 再谈Tcp协议3 程序重构3.1 Socket类3.2 回调函数设计3.3 最终的Tcp服务器类 1 初识序列化与反序列化 在刚学习计算机网络时&#xff0c;我们谈到过网络协议栈&#xff0c;其中最上层的就是应用层&#xff0c;那么这个应…

Qt圆角窗口

Qt圆角窗口 问题&#xff1a;自己重写了一个窗口&#xff0c;发现用qss设置圆角了&#xff0c;但是都不生效&#xff0c;不过子窗口圆角都生效了。 无边框移动窗口 bool eventFilter(QObject *watched, QEvent *evt) {static QPoint mousePoint;static bool mousePressed f…

开源、极简的B站第三方,建议所有人收藏

很多人说B站落寞了&#xff0c;但我觉得不是B站落寞&#xff0c;而是长视频落寞了。现代人已经没有充足的耐心&#xff0c;刷完一个十分钟的视频。毕竟&#xff0c;短视频可以把这十分钟切成50份&#xff0c;让我们开心50次。 可怕的是&#xff0c;B站即使落寞&#xff0c;在长…

继承的例题

答案&#xff1a;D 解析&#xff1a;C允许一个子类继承多个父类 知识点&#xff1a; 子类是父类的特殊化&#xff0c;父类是子类的泛化 解析&#xff1a;子类可以共享父类的属性和方法&#xff0c;选项A正确 面向对象关系中&#xff0c;类与类的关系包含继承&#xff0c;包…

IntelliJ IDEA 2024.1.4 (Ultimate Edition)找不到Add Framework Support解决方法

目录 背景: 解决方法&#xff1a; 步骤1: 步骤2&#xff1a; 步骤3&#xff1a; 创建Web项目的完整流程&#xff1a; 步骤1: 步骤2: 步骤3&#xff1a; 步骤4&#xff1a; Web优点: 背景: 我的IDE版本是IntelliJ IDEA 2024.1.4 (Ultimate Edition)&#xff0c;当我…

【优选算法之双指针】No.2--- 经典双指针算法(下)

文章目录 前言一、双指针示例&#xff1a;1.1 ⽔果成篮1.2 和为s的两个数字1.3 三数之和1.4 四数之和 二、双指针总结&#xff1a; 前言 &#x1f467;个人主页&#xff1a;小沈YO. &#x1f61a;小编介绍&#xff1a;欢迎来到我的乱七八糟小星球&#x1f31d; &#x1f4cb;专…

前后端分离,使用MOCK进行数据模拟开发,让前端攻城师独立于后端进行开发

mock是什么 Mock生成随机数据,拦截Ajax 请求&#xff0c;前后端分离&#xff0c;让前端攻城师独立于后端进行开发。 增加单元测试的真实性 通过随机数据,模拟各种场景。 在实际开发过程中&#xff0c;前端是通过axios来请求数据的&#xff0c;很多时候前端开发者就是通过写固定…

【Git必看系列】—— Git巨好用的神器之git stash篇

应用场景 当我们开发一个新功能时会先从master拉出一个分支dev&#xff0c;然后在这个dev分支下吭哧吭哧的开始写代码开发新功能&#xff0c;就如下代码所示&#xff0c;我们在dev分支下开发Person类的新功能getId() public class Person {private int id;private String nam…

Vue3:v-model实现组件通信

目录 一.性质 1.双向绑定 2.语法糖 3.响应式系统 4.灵活性 5.可配置性 6.多属性绑定 7.修饰符支持 8.defineModel使用 二.使用 1.父组件 2.子组件 三.代码 1.父组件代码 2.子组件代码 四.效果 一.性质 在Vue3中&#xff0c;v-model指令的性质和作用主要体现在…

vue3 快速入门系列 —— 基础

基础 前面我们已经用 vue2 和 react 做过开发了。 AIAutoPrediction 从 vue2 升级到 vue3 成本较大&#xff0c;特别是较大的项目。所以许多公司对旧项目继续使用vue2&#xff0c;新项目则使用 vue3。 有些UI框架&#xff0c;比如ant design vue1.x 使用的 vue2。但现在 an…

5.C++面向对象2(类对象大小计算,结构体内存对齐,大小端存储方式,this指针)

⭐本篇文章为C学习第4章&#xff0c;主要了解类对象大小和this指针 ⭐本人C代码仓库&#xff1a;yzc的c学习: 小川c的学习记录 - Gitee.com 目录 一. 类对象模型 1.1 类成员函数和成员变量的分布 1.2 如何计算类的大小&#xff1f;&#xff08;结构体内存对齐&#xff09…