Spring-AOP面相切面编程示例(有详细注释)

news2024/11/30 9:38:41

前提知识Spring-IOC容器注解方式使用icon-default.png?t=N7T8https://blog.csdn.net/m0_61160520/article/details/136784799?spm=1001.2014.3001.5501
切点表达式icon-default.png?t=N7T8https://blog.csdn.net/m0_61160520/article/details/136782885?spm=1001.2014.3001.5501

案例 

1.创建项目

2.导入依赖

    <dependencies>
        <!--spring context依赖-->
        <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.6</version>
        </dependency>
        <!--junit5测试-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>6.0.6</version>
        </dependency>
        <!-- spring整合aspectj框架的依赖 , 传到aspect框架依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.6</version>
        </dependency>
    </dependencies>

 3.准备并实现接口

package com.example.service;
public interface Calculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}
package com.example.service.impl;
import org.springframework.stereotype.Component;
@Component
public class CalculatorPureImpl  {
    public int add(int i, int j) {
        return i + j;
    }   

    public int sub(int i, int j) {
        return i - j;
    }
    
    public int mul(int i, int j) {
        return i * j;
    }
    
    public int div(int i, int j) {
        return i / j;
    }
}

4.实现配置类

package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy //开启aspectj的注解 <aop:aspectj-autoproxy />
public class JavaConfig {
}

5.配置切点

package com.example.pointcut;

import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
public class MyPointCut {
    //impl.*.*(..)意思是包下的某个类的某个方法
    @Pointcut("execution(* com.example.service.impl.*.*(..))")
    public void pc(){}

    @Pointcut("execution(* com..impl.*.*(..))")
    public void myPc(){}

}

6.定义增强类

package com.example.advice;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * description: 增强类的内部要存储增强代码
 *
 *   1. 定义方法存储增强代码
 *      具体定义几个方法,根据插入的位置决定!
 *   2. 使用注解配置 指定插入目标方法的位置
 *       前置   @Before
 *       后置   @AfterReturning
 *       异常   @AfterThrowing
 *       最后   @After
 *       环绕   @Around
 *
 *       try{
 *           前置
 *           目标方法执行
 *           后置
 *       }catch(){
 *           异常
 *       }finally{
 *           最后
 *       }
 *
 *   3. 配置切点表达式 [选中插入的方法   切点]
 *
 *   4.补全注解
 *      加入ioc容器 @Component
 *      配置切面  @Aspect  =  切点 + 增强
 *
 *   5.开启aspect注解的支持
 */
@Component
@Aspect
@Order(20)//多个增强类时,数字越小越先执行
public class LogAdvice {

    @Before("com.example.pointcut.MyPointCut.pc()")
    public void start(){
        System.out.println("方法开始了");
    }

    @After("com.example.pointcut.MyPointCut.pc()")
    public void after(){
        System.out.println("方法结束了");
    }

    @AfterThrowing("com.example.pointcut.MyPointCut.pc()")
    public void error(){
        System.out.println("方法报错了");
    }
}

7.定义测试类进行增强类测试

import com.example.config.JavaConfig;
import com.example.service.impl.CalculatorPureImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

@SpringJUnitConfig(value = JavaConfig.class)
public class SpringAopTest {
    // aop - 代理 - jdk - 接口 - 代理类  - 代理对象和目标对象 拜把子 兄弟关系 - 接口接值
    // 有aop - 在ioc中存储的是代理对象
    @Autowired
    private CalculatorPureImpl calculator;
    
    @Test
    public void test(){
        System.out.println("add = " + calculator.div(1, 1));
    }

}

8.获取目标方法信息并环绕通知方式

方法信息(方法名,参数,访问修饰符,所属的类的信息...)

 注意包为:import org.aspectj.lang.JoinPoint;

package com.example.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.util.logging.Logger;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;

/**
 * description:环绕通知,需要你在通知中,定义目标方法的执行!
 */
@Component
@Aspect
@Order(5)
public class TxAroundAdvice {
    private static Logger log = Logger.getLogger(TxAroundAdvice.class.toString());
// 使用@Around注解标明环绕通知方法
    @Around(value = "com.example.pointcut.MyPointCut.pc()")
    public Object manageTransaction(// 通过在通知方法形参位置声明ProceedingJoinPoint类型的形参,Spring会将这个类型的对象传给我们
            ProceedingJoinPoint joinPoint) {
        // 通过ProceedingJoinPoint对象获取外界调用目标方法时传入的实参数组
        Object[] args = joinPoint.getArgs();

        // 通过ProceedingJoinPoint对象获取目标方法的签名对象
        Signature signature = joinPoint.getSignature();

        // 通过签名对象获取目标方法的方法名
        String methodName = signature.getName();

        // 声明变量用来存储目标方法的返回值
        Object targetMethodReturnValue = null;

        try {
            // 在目标方法执行前:开启事务(模拟)
            log.info("[AOP 环绕通知] 开启事务,方法名:" + methodName + ",参数列表:" + Arrays.asList(args));

            // 过ProceedingJoinPoint对象调用目标方法
            // 目标方法的返回值一定要返回给外界调用者
            targetMethodReturnValue = joinPoint.proceed(args);

            // 在目标方法成功返回后:提交事务(模拟)
            log.info("[AOP 环绕通知] 提交事务,方法名:" + methodName + ",方法返回值:" + targetMethodReturnValue);
        }catch (Throwable e){
            // 在目标方法抛异常后:回滚事务(模拟)
            log.info("[AOP 环绕通知] 回滚事务,方法名:" + methodName + ",异常:" + e.getClass().getName());
        }finally {
            // 在目标方法最终结束后:释放数据库连接
            log.info("[AOP 环绕通知] 释放数据库连接,方法名:" + methodName);
        }
        return targetMethodReturnValue;
    }
}

 运行测试

 

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

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

相关文章

CSS 三大特性 详细讲解

CSS 三大特性及代码解释 层叠性 当相同选择器设置相同样式且发生冲突时&#xff0c;此时后者的样式会覆盖&#xff08;层叠&#xff09;前者冲突样式。CSS的层叠性就是用于解决样式冲突问题。 Input&#xff1a; <style>div {color: red;}div { color: blue; <!-…

webconfig-boot分布式项目Web一站式配置

1、前言 最近利用空余时间写了一个项目webconfig-boot 。该项目主要配置了web项目常用的一些配置&#xff0c;如统一参数校验、统一异常捕获、统一日期的处理、常用过滤器、常用注解等。引入依赖接口完成常规的web配置。 这里也是总结了笔者在项目开发中遇到的一些常用的配置…

springboot项目讲解

技术栈 vue(前端) springboot(后端主框架) mybatis&#xff08;ORM&#xff0c;用于后端和数据库的映射&#xff0c;即java对象转换成表&#xff09; mysql (关系型数据库) 顶层结构 .idea&#xff1a; idea缓存文件(不需要管) src&#xff1a;代码核心文件夹 —main&#xf…

Windows Terminal配置 美化

Windows 终端自定义提示符设置 | Microsoft Learn 安装PowerShell7 在 Windows 上安装 PowerShell - PowerShell | Microsoft Learn 设置默认为 PowerShell7 安装 在powerShell 开启远程权限 Set-ExecutionPolicy RemoteSigned -scope CurrentUserscoop 执行 iwr -useb ht…

王道机试C++续第6章 数学问题 贪心算法和蓝桥杯真题Day37倒计时24天

6.4 分解质因数 上一节讨论了素数的问题&#xff0c;而素数常用于分解质因数。每个数都可以写成一个或几个质数相乘的形式&#xff0c;其中每个质数都是这个数的质因数。把一个数用质因数相乘的形式表示出来&#xff0c;就称为分解质因数。例如&#xff0c;对一个数 x 分解素…

Centos7没有可用软件包 ifconfig问题解决

问题描述 在Centos7中查看ip没有ifconfig&#xff0c;使用yum安装ifconfig报错没有可用软件包 ifconfig问题解决 [rootlocalhost etc]# yum -y install ifconfig 已加载插件&#xff1a;fastestmirror base …

进程间通信 之 共享内存

目录 什么是共享内存&#xff1f; 共享内存的系统调用接口 共享内存 进程间通信的本质及前提&#xff1a;让不同的进程看到同一份资源&#xff01; 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间&#xff0c;这些进程间数据传递不再涉及到内核&a…

鸿蒙开发实战:【网络管理-Socket连接】

介绍 本示例主要演示了Socket在网络通信方面的应用&#xff0c;展示了Socket在两端设备的连接验证、聊天通信方面的应用。 效果预览 使用说明 1.打开应用&#xff0c;点击用户文本框选择要登录的用户&#xff0c;并输入另一个设备的IP地址&#xff0c;点击确定按钮进入已登录…

【毛毛讲书】【好运】为什么有些人天生就有好运眷顾?

重磅专栏推荐&#xff1a; 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域&#xff0c;包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用&#xff0c;以及与之相关的人工智能生成内容&#xff…

什么是web组态?Web组态软件哪个好用?

随着工业4.0的到来&#xff0c;物联网、大数据、人工智能等技术的融合应用&#xff0c;使得工业领域正在经历一场深刻的变革。在这个过程中&#xff0c;Web组态技术以其独特的优势&#xff0c;正在逐渐受到越来越多企业的关注和认可。那么&#xff0c;什么是Web组态&#xff1f…

轻巧的elasticsearch可视化工具

一、概述 常见的ES可视化工具有&#xff1a; kibanaelasticsearch-headElasticHDDejavucerebroelasticview 一、安装elasticview 在众多ES可视化龚居中&#xff0c;elasticview是一款比较轻量简洁&#xff0c;兼容性较好&#xff0c;可以兼容多个ES版本&#xff0c;不但可以进…

[蓝桥杯 2020 省 AB3] 限高杆

分层图建图典题 #include<bits/stdc.h> using namespace std; using ll long long; #define int long long const int N 6e510; const int inf 0x3f3f3f3f; const int mod 1e97; int e[N],ne[N],w[N],h[N],idx; void add(int a,int b,int c){e[idx] b,ne[idx] h[a]…

外键约束

目录 外键约束 对数据表进行初期设计&#xff0c;暂时不使用外键 验证限制三 验证级联删除 设置级联更新 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 外键约束 外键约束主要是在父子表关系中体现的一种约束操作。…

【二叉树】算法例题

目录 九、二叉树 68. 二叉树的最大深度 ① 69. 相同的树 ① √ 70. 翻转二叉树 ① 71. 对称二叉树 ① 72. 从前序与中序遍历序列构造二叉树 ② 73. 从中序与后续遍历序列构造二叉树 ② 74. 填充每个节点的下一个右侧节点指针 II ② 75. 二叉树展开为链表 ② 76.…

鸿蒙实战开发:【FaultLoggerd组件】讲解

简介 Faultloggerd部件是OpenHarmony中C/C运行时崩溃临时日志的生成及管理模块。面向基于 Rust 开发的部件&#xff0c;Faultloggerd 提供了Rust Panic故障日志生成能力。系统开发者可以在预设的路径下找到故障日志&#xff0c;定位相关问题。 架构 Native InnerKits 接口 Si…

Marin说PCB之电源完整性之直流压降仿真CST--03

本期内容主要讲解的是关于在CST软件上电源直流压降仿真VRM的一些相关参数设置&#xff0c;小编我在之前文章中有说到过如何利用CST仿真电源信号的直流压降&#xff0c;不过有一些问题我这边再去补充一些。 首先就是VRM芯片的设置了&#xff0c;小编我还是按照之前那样设置&…

腾讯云k8s容器服务

1、新建一个集群 这个网址&#xff1a; 登录登录 - 腾讯云 2、选择第一个 3、名字随便起一个&#xff0c;然后基本默认就行 4、 组件配置直接跳过&#xff0c;信息确认&#xff0c;等待集群初始化&#xff0c;等10分钟左右&#xff08;容器服务需要充点钱才行&#xff09; 5…

学习vue3第八节(自定义指令 directive)

1、自定义指令的作用&#xff1a; 自定义指令是用来操作底层DOM的&#xff0c;尽管vue推崇数据驱动视图的理念&#xff0c;但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和拓展&#xff0c;不仅仅可用于定义任何DOM操作&#xff0c;并且是可以重复使用。 自定义…

杨氏矩阵的查找(复杂度<O(N))

题目&#xff1a; 解释&#xff1a;时间复杂度小于O(N)即不要一个一个的去遍历查找。 思路&#xff1a; 一个33的二维数组如图所示&#xff1a; 一&#xff1a;先找到一个最关键的数字&#xff0c;3&#xff08;下标为0,2&#xff09; 关键数的关键之处在于&#xff08;处于…

过拟合欠拟合

问题&#xff1a;训练数据训练的很好啊&#xff0c;误差也不大&#xff0c;为什么在测试集上面有问题呢&#xff1f; 当算法在某个数据集当中出现这种情况&#xff0c;可能就出现了过拟合现象。 1、 什么是过拟合与欠拟合 欠拟合 过拟合 分析第一种情况&#xff1a;因为机器…