Spring AOP简介及相关案例

news2024/11/19 19:31:59

目录

一、Spring AOP简介

二、AOP相关术语

三、AOP入门案例

1. 引入依赖

2. 编写连接点

3. 编写通知类

4. 配置切面

5. 测试 

四、通知类型

1. 编写通知方法

2. 配置切面

3. 测试

五、切点表达式

六、多切面配置 

1. 编写发送邮件的通知

2. 配置切面

3. 测试 

往期专栏&文章相关导读 

1. Maven系列专栏文章

2. Mybatis系列专栏文章

3. Spring系列专栏文章 


一、Spring AOP简介

        AOP的全称是Aspect Oriented Programming,即面向切面编程。是实现功能统一维护的一种技术,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。

  • 作用:在不修改源码的基础上,对已有方法进行增强。实现原理:动态代理技术。
  • 优势:减少重复代码、提高开发效率、维护方便
  • 应用场景:事务处理、日志管理、权限控制、异常处理等方面。

二、AOP相关术语

 为了更好地理解AOP,就需要对AOP的相关术语有一些了解

名称 说明
Joinpoint(连接点)指能被拦截到的点,在Spring中只有方法能被拦截。
Pointcut(切点)指要对哪些连接点进行拦截,即被增强的方法。
Advice(通知)指拦截后要做的事情,即切点被拦截后执行的方法。
Aspect(切面)切点+通知称为切面
Target(目标)被代理的对象
Proxy(代理)代理对象
Weaving(织入)生成代理对象的过程

三、AOP入门案例

AspectJ是一个基于Java语言的AOP框架,在Spring框架中建议使用AspectJ实现AOP。
接下来我们写一个AOP入门案例:dao层的每个方法结束后都可以打印一条日志:

1. 引入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.13</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
    </dependencies>

2. 编写连接点

package com.example.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    public void add(){
        System.out.println("用户新增");
    }
    public void delete(){
        System.out.println("用户删除");
    }
    public void update(){
        System.out.println("用户修改");
    }
}

3. 编写通知类

package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

public class MyAspectJAdvice {
    // 后置通知
    public void myAfterReturning(JoinPoint joinPoint){
        System.out.println("切点方法名:"+joinPoint.getSignature().getName());
        System.out.println("目标对象:"+joinPoint.getTarget());
        System.out.println("打印日志···"+joinPoint.getSignature().getName()+"方法被执行了!");    }
}

4. 配置切面

bean.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://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">
        <!-- 扫描包 -->
        <context:component-scan base-package="com.example"/>
        <!-- 通知对象 -->
        <bean id="myAspectJAdvice" class="com.example.aspect.MyAspectJAdvice"/>
        <!-- 配置AOP -->
        <aop:config>
            <!-- 配置切面 -->
            <aop:aspect ref="myAspectJAdvice">
                <!-- 配置切点 -->
                <aop:pointcut id="myPointcut" expression="execution(* com.example.dao.UserDao.* (..))"/>
                <!-- 配置后置通知 -->
                <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/>
            </aop:aspect>
        </aop:config>
  </beans>

5. 测试 

import com.example.SpringConfig;
import com.example.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserDaoTest {
    @Test
    public void testAdd(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        UserDao userDao = (UserDao) ac.getBean("userDao");
        userDao.add();
    }
    @Test
    public void testDelete(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        UserDao userDao = (UserDao) ac.getBean("userDao");
        userDao.delete();
    }
}

运行结果分别为

 

  

OK,确实是可以的,本次入门案例就学习到这里了。 

四、通知类型

 AOP有以下几种常用的通知类型:

通知类型描述
前置通知在方法执行前添加功能
后置通知在方法正常执行后添加功能
异常通知在方法抛出异常后添加功能
最终通知无论方法是否抛出异常,都会执行该通知
环绕通知在方法执行前后添加功能

1. 编写通知方法

    // 前置通知
    public void myBefore(){
        System.out.println("前置通知···");
    }

    // 异常通知
    public void myAfterThrowing(Exception e){
        System.out.println("异常通知···");
        System.out.println(e.getMessage());
    }

    // 最终通知
    public void myAfter(){
        System.out.println("最终通知···");
    }

    // 环绕通知
    public Object myAround(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前···");
        // 执行方法
        Object obj = point.proceed();
        System.out.println("环绕后···");
        return obj;
    }

2. 配置切面

        <!-- 配置AOP -->
        <aop:config>
            <!-- 配置切面 -->
            <aop:aspect ref="myAspectJAdvice">
                <!-- 配置切点 -->
                <aop:pointcut id="myPointcut" expression="execution(* com.example.dao.UserDao.* (..))"/>
                <!-- 配置后置通知 -->
                <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/>
                <!-- 前置通知 -->
                <aop:before method="myBefore" pointcut-ref="myPointcut"/>
                <!-- 异常通知 -->
                <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/>
                <!-- 最终通知 -->
                <aop:after method="myAfter" pointcut-ref="myPointcut"/>
                <!-- 环绕通知 -->
                <aop:around method="myAround" pointcut-ref="myPointcut"/>
            </aop:aspect>
        </aop:config>

3. 测试

OK,这里我们测试用户新增方法 ,确实是得出来我们想要的结果了

五、切点表达式

切点表达式:访问修饰符 返回值 包名.类名.方法名(参数列表)

  • 使用AspectJ需要使用切点表达式配置切点位置,写法如下:
  • 标准写法:访问修饰符 返回值 包名.类名.方法名(参数列表)
  • 访问修饰符可以省略。
  • 返回值使用 * 代表任意类型。
  • 包名使用 * 表示任意包,多级包结构要写多个 * ,使用 *.. 表示任意包结构
  • 类名和方法名都可以用 * 实现通配。

参数列表

  • 基本数据类型直接写类型
  • 引用类型写 包名.类名
  • * 表示匹配一个任意类型参数
  • .. 表示匹配任意类型任意个数的参数

全通配: * *..*.*(..)

六、多切面配置 

        我们可以为切点配置多个通知,形成多切面,比如希望dao层的每个方法结束后都可以打印日志并发送邮件:

1. 编写发送邮件的通知

package com.example.aspect;

import org.aspectj.lang.JoinPoint;

public class MyAspectJAdvice2 {
    // 后置通知
    public void myAfterReturning(JoinPoint point){
        System.out.println("发送邮件···");
    }
}

2. 配置切面

在上面的基础上配置多一个切面即可

    <aop:aspect ref="myAspectJAdvice2">
         <aop:pointcut id="myPointcut2" expression="execution(* com.example.dao.UserDao.*(..))"/>
         <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut2"/>
    </aop:aspect>

3. 测试 

        OK,确实是打印了发送邮件,因此该多切面配置成功,下面接着讲解用另外几种方法实现AOP ,让我们一起学习啪

往期专栏&文章相关导读 

     大家如果对于本期内容有什么不了解的话也可以去看看往期的内容,下面列出了博主往期精心制作的Maven,Mybatis等专栏系列文章,走过路过不要错过哎!如果对您有所帮助的话就点点赞,收藏一下啪。其中Spring专栏有些正在更,所以无法查看,但是当博主全部更完之后就可以看啦。

1. Maven系列专栏文章

Maven系列专栏Maven工程开发
Maven聚合开发【实例详解---5555字】

2. Mybatis系列专栏文章

Mybatis系列专栏MyBatis入门配置
Mybatis入门案例【超详细】
MyBatis配置文件 —— 相关标签详解
Mybatis模糊查询——三种定义参数方法和聚合查询、主键回填
Mybatis动态SQL查询 --(附实战案例--8888个字--88质量分)
Mybatis分页查询——四种传参方式
Mybatis一级缓存和二级缓存(带测试方法)
Mybatis分解式查询
Mybatis关联查询【附实战案例】
MyBatis注解开发---实现增删查改和动态SQL
MyBatis注解开发---实现自定义映射关系和关联查询

3. Spring系列专栏文章 

Spring系列专栏Spring IOC 入门简介【自定义容器实例】
IOC使用Spring实现附实例详解
Spring IOC之对象的创建方式、策略及销毁时机和生命周期且获取方式
Spring DI简介及依赖注入方式和依赖注入类型
Spring IOC相关注解运用——上篇
Spring IOC相关注解运用——下篇
Spring AOP简介及相关案例
注解、原生Spring、SchemaBased三种方式实现AOP【附详细案例】
Spring事务简介及相关案例
Spring 事务管理方案和事务管理器及事务控制的API
Spring 事务的相关配置、传播行为、隔离级别及注解配置声明式事务

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

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

相关文章

flex 布局的基本概念 - 详解

flex 布局的基本概念 Flexible Box 模型&#xff0c;通常被称为 flexbox&#xff0c;是一种一维的布局模型。它给 flexbox 的子元素之间提供了强大的空间分布和对齐能力。本文给出了 flexbox 的主要特性&#xff0c;更多的细节将在别的文档中探索。我们说 flexbox 是一种一维的…

Metasploit超详细安装及使用教程(图文版)

通过本篇文章&#xff0c;我们将会学习以下内容&#xff1a; 1、在Windows上安装Metasploit 2、在Linux和MacOS上安装Metasploit 3、在Kali Linux中使用 Metasploit 4、升级Kali Linux 5、使用虚拟化软件构建渗透测试实验环境 6、配置SSH连接 7、使用SSH连接Kali 8、配…

C++ vector与map的结合运用

目录 vector和map的简单介绍&#xff1a; 今天我们用vector容器和map容器实现以下简单的功能&#xff1a; 案例描述&#xff1a; 图解: ​ 实现步骤&#xff1a; 代码实现&#xff1a; 运行结果&#xff1a; vector和map的简单介绍&#xff1a; map和vector都是C STL&…

C++11 -- 包装器

文章目录 function包装器function包装器的概念function的运用function实例化使用function解决逆波兰表达式 bind包装器bind包装器相关介绍bind绑定函数固定参数 function包装器 function包装器的概念 function包装器,也叫做适配器,它的本质是一个类模板. 例如: 1 template&l…

chatgpt赋能python:Python中的迭代器

Python中的迭代器 在Python中&#xff0c;迭代器是一种对象&#xff0c;它可以让我们可以遍历&#xff08;或迭代&#xff09;序列中的元素而不必了解它们如何存储在内存中。迭代器是Python中许多高级构造的基础 - 他们节省了空间&#xff0c;并且它们能够帮助我们更有效地处理…

Redis高级篇 - 多级缓存

多级缓存 1.什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈 Redis缓存失效时…

VUE项目运行失败原因以及解决办法(以vscode为例)

1.正常运行&#xff1a; Ctl J打开终端&#xff0c;并运行如下命令&#xff1a; npm run serve 正常情况下&#xff0c;就可以得到本地和网络链接&#xff0c;如下&#xff1a; 点击链接即可进入到编辑好的页面。 不过&#xff0c;你也可能遇到如下情况↓↓↓ 2.无法找到pac…

创建第一个.NET MAUI应用

1.打开VS2022,创建新项目,并选择.NET MAUI应用,然后点击下一步 2.输入项目相关配置,然后点击下一步 3. 选择框架版本,然后点击创建 4.项目创建成功后会自动打开概述页 5.平台框架切换 6.启动应用,如有下图提示,启动开发者模式 成功启动应用 7.修改应用 修改MainPage.xml如下图…

Baumer工业相机堡盟工业相机如何使用CameraExplorer软件设置MultiROI模式以及该模式的优势以及行业应用

Baumer工业相机堡盟工业相机如何使用MultiROI模式以及该模式的优势以及行业应用 Baumer工业相机Baumer工业相机的MultiROI模式的技术背景Baumer工业相机使用CameraExplorer软件设置MultiROI模式1.开启Baumer工业相机MultiROI模式2.关闭Baumer工业相机MultiROI模式3.测试使用Bau…

C++ 排序算法

&#x1f914;排序算法&#xff1a; &#x1f4d6;1.sort 对容器内元素进行排序 &#x1f4d6;2.random_shuffle 洗牌 指定范围内的元素随机调整次序 &#x1f4d6;3.merge 容器元素合并&#xff0c;并整合到另一个容器中 &#x1f4d6;4.reverse 反转指定容…

强推宝藏网站

最近还是有很强烈的感受&#xff0c;方法大于努力。最近就整理了一下大学期间比较好用的网站&#xff0c;也陪我度过了一段时间了&#xff0c;排名不分先后&#xff0c;把压箱底的东西拿出来了。 ChatGPT WeTab 新标签页https://www.wetab.link/ChatGPT国内免费使用方法有哪些…

【数据结构6】二叉树的基本操作

文章目录 ⭐️写在前面的话⭐️二叉树的一些基本操作1、结构定义2、先序创建这棵树3、按满二叉树方式创建4、三种递归遍历5、层次遍历6、求二叉树的深度7、求叶子结点数8、三种非递归遍历9、先序线索化二叉树10、先序线索化后遍历11、中序线索化二叉树12、中序线索化后遍历主函…

MySQL进阶- SQL优化和视图

目录 SQL优化插入数据时的SQL优化&#xff08;insert优化&#xff0c;和大批量数据插入&#xff09;主键优化order by优化&#xff08;排序操作的优化&#xff09;group by优化&#xff08;分组优化&#xff09;limit优化&#xff08;分页查询优化&#xff09; SQL优化 插入数…

[RUST/腐蚀]Windows-开服服务端下载以及配置

一、前置要求 1.SteamCMD&#xff1a;SteamCMD - Valve Developer Communityhttps://developer.valvesoftware.com/wiki/SteamCMD 2.通过SteamCMD下载RUST/腐蚀服务端。 二、SteamCMD 注意&#xff1a;所有目录均应避免出现中文。 1.建立SteamCMD文件夹&#xff0c;如 D:\st…

准备入门python的一些建议

提醒&#xff1a;一下内容只代表个人观点 从18年左右开始&#xff0c;python的广告就被打得满天飞&#xff0c;网上各种吹嘘python这门语言的广告五花八门&#xff0c;当然也有一些人看完这些广告后感觉python非常的高大上&#xff0c;然后就入门学习了python&#xff0c;我就…

【测试基础02】

测试基础02 一、HTML基础二、Python导入三方模块三、安装webgrock驱动四、元素定位(1)、元素定位工具(2)、元素定位方式(3)、XPATH路径(3)、CSS选择器 五、Selenium WebDriver初步应用(1)、基本方法(2)、测试案例1(3)、测试案例2(3)、测试案例3 六、获取元素信息的方法七、fram…

价值5000元以上的某马大数据全套视频【强烈推荐】

某马大数据 01、阶段一 Python大数据开发基础 01、第一章大数据介绍及开发环境 02、第二章 linux命令 03、第三章 MySQL数据库 04、第四章 excel的使用 05、第五章 kettle的使用 06、第六章 数据分析及可视化 07、第七章 大数据框架与数仓基础 08、第八章 数仓实战项目 …

3-网络初识——协议

目录 1.概念 ①语法&#xff1a;即数据与控制信息的结构或格式。 ②语义&#xff1a;即需要发出何种控制信息&#xff0c;完成何种动作以及做出何种响应。 ③时序&#xff1a;即事件实现顺序的详细说明。 2.作用 3.知名协议的默认端口 4.协议分层 4.1.什么是协议分层 …

chatgpt赋能python:Python中的转置操作:理解与实践

Python中的转置操作&#xff1a;理解与实践 在Python中&#xff0c;可以使用转置操作来将矩阵或数组的行和列交换位置。转置操作不仅在数学和统计学上有广泛应用&#xff0c;也在机器学习和数据分析领域中非常重要。在本文中&#xff0c;我们将深入探讨Python中的转置操作的基…

C# | 使用Memory<T>高效地读写内存数据

C# | 使用Memory高效地读写内存数据 文章目录 C# | 使用Memory<T>高效地读写内存数据前言Memory<T>介绍示例结束语 前言 Memory<T>是C# 7.2版本中引入的一种新类型&#xff0c;可以更加高效地读写内存数据。本文将介绍它的用途以及如何使用它来优化代码。 P…