springboot-aop-学习笔记

news2024/11/20 20:44:10

什么是AOP?

  • AOP英文全称:Aspect Oriented Programming(面向切面编程、面向方面编程),其实说白了,就是 需要 某个通用的方法时,可以创建一个模板,模板里面就有这些通用的方法,然后再把需要这些方法的方法们嵌套进去运行,很像动态代理

同时需要增加一个方法,改动原来的代码很麻烦,所以直接使用一个模板来调用原来的代码,模板里面就有需要增加的方法:

这么说可能还有点抽象,举个例子,现在需要给项目中逻辑层每个方法添加一个记录运行耗时的功能,如果在每个方法里面都敲上这么一段新增的代码即麻烦又显得代码臃肿,这个时候就可以使用AOP:

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect //声明为AOP类
@Component
public class TimeAspect {

    @Around("execution(* com.zeyu.service.*.*(..))") //切入点表达式,声明要生效的范围
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        //1、记录开始时间
        long begin = System.currentTimeMillis();

        //2、调用原始方法运行
        Object result = joinPoint.proceed();

        //3、记录结束时间,计算方法执行耗时
        long end = System.currentTimeMillis();
        log.info(joinPoint.getSignature() + "方法执行耗时{}ms", end - begin);

        return result;
    }

}

 如上述代码,在执行逻辑层每个方法前都会先进行记录开始时间的操作,然后再执行目标方法,目标方法结束之后,再记录结束时间,再输出耗时,这样不仅节省了代码量,也更加便于维护管理

AOP的核心概念:

1. 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)

2. 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)

3.切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用

4.切面:Aspect,描述通知与切入点的对应关系(通知+切入点)

5.目标对象:Target,通知所应用的对象

AOP的运用

第一步:导入依赖

在pom.xml文件中添加AOP的起步依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

第二步,编写程序:

建议新建一个aop包专门放aop程序

一个aop程序的规范有如下几点

  • 类声明:必须在类上添加@Aspect注解声明当前类为切面类
  • 方法声明:必须在方法上添加@通知类型注解(切入点表达式),声明通知类型和切入点范围
  • 如果通知类型为Around,需要定义ProceedingJoinPoint  joinPoint形参(形参名可自定义),并使用joinPoint的process方法调用连接点
  • 如果同通知类型的aop程序有多个,可以添加@Order()注解设置执行优先级,直接在括号里面填写数字,数字越小越先执行

AOP的通知类型:

  • @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行

  • @Before:前置通知,此注解标注的通知方法在目标方法前被执行

  • @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行

  • @AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行

  • @AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行

AOP的切入点表达式:

一、@execution

主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:

execution(访问修饰符?  返回值  包名.类名.?方法名(方法参数) throws 异常?)

其中带?的表示可以省略的部分

  • 访问修饰符:可省略(比如: public、protected)

  • 包名.类名: 可省略

  • throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)

示例:

@Before("execution(void com.zeyu.service.impl.DeptServiceImpl.delete(java.lang.Integer))")

可以使用通配符描述切入点

  • * :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分

  • .. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数

切入点表达式的语法规则:

  1. 方法的访问修饰符可以省略

  2. 返回值可以使用*号代替(任意返回值类型)

  3. 包名可以使用*号代替,代表任意包(一层包使用一个*

  4. 使用..配置包名,标识此包以及此包下的所有子包

  5. 类名可以使用*号代替,标识任意类

  6. 方法名可以使用*号代替,表示任意方法

  7. 可以使用 * 配置参数,一个任意类型的参数

  8. 可以使用.. 配置参数,任意个任意类型的参数

注意事项:

  • 根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式

execution(* com.zeyu.service.DeptService.list(..)) || execution(* com.zeyu.service.DeptService.delete(..))

切入点表达式的书写建议:

  • 所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是 find 开头,更新类方法都是update开头

二、@annotation

适用于无规则匹配

需要:

编写自定义注解

在作为连接点的方法上添加自定义注解

自定义注解不需要再添加特别的注解,只需要声明作用范围和生效时间即可

例:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OPLog {
}

 像这样定义好一个自定义注解好,再去需要使用aop的连接点业务方法上添加自定义注解,例:

@OPLog
    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }

    //rollbackFor = Exception.class 表示所有异常都会触发回滚,rollbackFor = ? 指定什么异常会回滚事务,默认是运行时异常将回滚
    @OPLog
    @Transactional(rollbackFor = Exception.class)     //事务管理Transactional  如果打上该注解的方法、对象、接口出现异常,就会进行回滚
    @Override
    public void delete(Integer id) {

        try {
            deptMapper.deleteById(id);  //根据id删除部门
            empService.deleteByDeptId(id);  //根据部门id删除员工
        } finally {
            DeptLog deptlog = new DeptLog();
//            deptlog.setCreateTime(LocalDateTime.now());
//            deptlog.setOperation("执行了解散部门的操作,此次解散的是" + id + "号部门");
//            deptLogService.insert(deptlog);
        }

    }

    @OPLog
    @Override
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }

    @OPLog
    @Override
    public void upadte(Dept dept) {
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.update(dept);
    }


    @OPLog
    @Override
    public Dept getById(Integer id) {
        Dept dept = deptMapper.getById(id);
        return dept;
    }

 打上注解之后,再在AOP程序上的通知类型注解里面使用@annotation注解声明范围,例:

@Pointcut("@annotation(com.zeyu.aop.OPLog)")
    public void log()

如此,该通知的切入点范围就是那些添加了自定义注解的业务方法

@Pointcut

如果有多个通知的切入点范围都是同一个切入点表达式,则可以把该切入点表达式提取出来:
创建一个方法,不需要方法体,在其上添加@Pointcut注解,注解value值为提取出来的切入点表达式,然后在需要使用该切入点表达式的通知注解里写上该方法名即可,示例:

连接点

前面有提到,在Around类型通知里,获取连接点信息需要在形参列表里定义一个ProceedingJoinPoint类型的形参,如果需要调用连接点,则使用该形参的process方法

而在其它类型通知里,获取连接点信息需要的是JoinPoint类型的形参,它是ProceedingJoinPoint的父类型

通过该形参,可以获取连接点的各种信息

下面是一个记录日志的例子,其中就用到了很多连接点信息:

package com.zeyu.aop;

import com.alibaba.fastjson.JSONObject;
import com.zeyu.pojo.OperateLog;
import com.zeyu.service.OperateLogService;
import com.zeyu.utils.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Map;

@Slf4j
@Aspect
@Component
public class OperateLogAspect { //操作日志

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private OperateLogService operateLogService;

    @Pointcut("@annotation(com.zeyu.aop.OPLog)")
    public void log(){}


    @Around("log()")
    public Object record(ProceedingJoinPoint JoinPoint) throws Throwable {
        log.info("开始记录本次操作...");

        //记录日志
        OperateLog operateLog = new OperateLog();
        //操作人ID
        String jwt = request.getHeader("token");
        Map<String, Object> claims = JwtUtils.parseJWT(jwt);
        operateLog.setOperateUser((Integer) claims.get("id"));
        //操作类名
        operateLog.setClassName(JoinPoint.getTarget().getClass().getName());
        //操作方法名
        operateLog.setMethodName(JoinPoint.getSignature().getName());
        //操作方法参数
        operateLog.setMethodParams(Arrays.toString(JoinPoint.getArgs()));

        long start = System.currentTimeMillis();
        //执行目标方法
        Object proceed = JoinPoint.proceed();
        long end = System.currentTimeMillis();

        //方法返回值
        operateLog.setReturnValue(JSONObject.toJSONString(proceed));
        //操作耗时
        operateLog.setCostTime(end - start);

        operateLogService.insert(operateLog);

        return proceed;
    }
}

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

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

相关文章

mysql 其他类型转换为BIT

看官网说明,BIT没什么特殊之处。但实际操作却不能将任何其他类型字段转为BIT,下面两个都报语法错误 CAST(column AS BIT(1)) AS aa , CAST(column AS BIT) AS bb, BIT value则模式是VARBINARY b1 as cc, -- cc为VARBINARY类型 下面是《高性能MySQL(第四版)》中关于BIT类型的…

JDK不同版本里中国夏令时时间

什么是夏令时&#xff1f; 夏令时&#xff0c;&#xff08;Daylight Saving Time&#xff1a;DST&#xff09;&#xff0c;也叫夏时制&#xff0c;又称“日光节约时制”和“夏令时间”&#xff0c;是一种为节约能源而人为规定地方时间的制度&#xff0c;在这一制度实行期间所采…

物业收费管理小程序源码搭建/部署/上线/运营/售后/更新

一款基于FastAdminUniApp开发的一款物业收费管理小程序。包含房产管理、收费标准、家属管理、抄表管理、在线缴费、业主公告、统计报表、业主投票、可视化大屏等功能。为物业量身打造的小区收费管理系统&#xff0c;贴合物业工作场景&#xff0c;轻松提高物业费用收缴率&#x…

代码随想录算法训练营第六十天| LeetCode647. 回文子串 、516.最长回文子序列

一、LeetCode647. 回文子串 题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/0647.%E5%9B%9E%E6%96%87%E5%AD%90%E4%B8%B2.html 状态&#xff1a;已解决 1.思路 这道题我只想出来了暴力解法&#xff0c;动规解法并没有想出来。根据视频讲解才把它想出来。…

MT8370_联发科MTK8370(Genio 510)芯片性能规格参数

MT8370芯片是一款利用超高效的6nm制程工艺打造的边缘AI平台&#xff0c;具有强大的性能和功能。这款芯片集成了六核CPU(2x2.2 GHz Arm Cortex-A78 & 4x2.0 GHz Arm Cortex-A55)、Arm Mali-G57 MC2 GPU、集成的APU(AI处理器)和DSP&#xff0c;以及一个HEVC编码加速引擎&…

zip file is empty

从下找到报错的jar包。展开这个jar包&#xff0c;看下是否正常&#xff0c;正常的是能够展开看到一些文件夹以及里面的类&#xff0c;如下&#xff1a;如果不正常&#xff0c;就删除这个jar包&#xff0c;同时找到这个jar包在本地maven仓库的地址&#xff0c;也删除掉&#xff…

鸿蒙内核源码分析(文件句柄篇) | 你为什么叫句柄

句柄 | handle int open(const char* pathname,int flags); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); int close(int fd);只要写过应用程序代码操作过文件不会陌生这几个函数,文件操作的几个关键步骤嘛,跟把大…

ssrf漏洞学习——基础知识

一、SSRF是什么&#xff1f; SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。 一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。&#xff08;正是因为它是由服务端发起的&#xff0c;所以它能…

天府锋巢直播产业基地构建成都电商直播高地

天府锋巢直播产业基地自成立以来&#xff0c;一直秉承着创新、协同、共赢的发展理念&#xff0c;吸引了众多直播企业纷纷入驻。随着直播产业的迅猛发展&#xff0c;改成都直播基地内的配套服务也显得尤为重要。本文将深入探讨入驻天府锋巢直播产业基地后&#xff0c;配套的直播…

Agent AI智能体:我们的生活即将如何改变?

你有没有想过&#xff0c;那个帮你设置闹钟、提醒你朋友的生日&#xff0c;甚至帮你订外卖的智能助手&#xff0c;其实就是Agent AI智能体&#xff1f;它们已经在我们生活中扮演了越来越重要的角色。现在&#xff0c;让我们一起想象一下&#xff0c;随着这些AI智能体变得越来越…

20240510每日后端---聊聊文件预览,doc,image,ppt转PDF预览

一、引入依赖 <dependency><groupId>com.aspose</groupId><artifactId>aspose-words</artifactId><version>15.8</version></dependency><dependency><groupId>com.aspose</groupId><artifactId>crac…

从头开始的建材类电商小程序开发指南

在当今数字化时代&#xff0c;小程序已经成为了许多企业推广和销售的重要渠道。对于建筑材料行业来说&#xff0c;开发一个属于自己的小程序商城不仅可以提升产品曝光度&#xff0c;还可以提供更好的用户购物体验。下面&#xff0c;我们将逐步教你如何开发建筑材料行业小程序。…

佛山市举办2024年护士节庆祝活动

“作为一名在护理岗位上工作了39年的护士,能够在退休前参加这样温情的护士节活动,获得一个纪念胸章和一份荣誉证书,让我很感动!”第七届“南粤好护士”、佛山市第一人民医院急诊科护士长罗银秋说道。5月10日下午,由佛山市卫生健康局主办、佛山市护理学会协办、佛山市第一人民医…

CSS-页面导航栏实现-每文一言(过有意义的生活,做最好的自己)

&#x1f390;每文一言 过有意义的生活,做最好的自己 目录 &#x1f390;每文一言 &#x1f6d2;盒子模型 &#x1f453;外间距 (margin) &#x1f97c;边框 &#x1f45c;内边距 切换盒子模型计算方案&#xff1a; &#x1f3a2; 浮动布局 浮动特点 &#x1f3c6;导航…

wandb: - 0.000 MB of 0.011 MB uploaded持续出现的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Ubuntu系统下编译OpenCV4.8源码

OpenCV4.8源码编译与安装 其实很简单&#xff0c;只要三步即可搞定&#xff0c;第一步是下载指定版本的源码包&#xff1b;第二步是安装OpenCV4.8编译需要的编译器与第三方库支持&#xff1b;第三步就是编译OpenCV源码包生成安装文件并安装。 01下载OpenCV4.8源码包 在Ubunt…

智慧公厕,运用数据提升公共厕所管理水平!

随着城市人口的增加和生活水平的提高&#xff0c;公共厕所的管理变得越来越重要。传统的厕所管理方式已经无法满足人们对卫生、便利和舒适的需求。而智慧公厕作为新一代公厕管理方式&#xff0c;通过运用数据技术和大数据分析手段&#xff0c;彻底改变了公厕管理的模式&#xf…

【系统架构师】-案例篇(七)信息安全

某软件公司拟开发一套信息安全支撑平台&#xff0c;为客户的局域网业务环境提供信息安全保护。该支撑平台的主要需求如下&#xff1a; 1.为局域网业务环境提供用户身份鉴别与资源访问授权功能&#xff1b; 2.为局域网环境中交换的网络数据提供加密保护&#xff1b; 3.为服务…

真驱鸟农业专用插电款驱鸟器,防喜鹊、麻雀各种鸟类

成年喜鹊的栖息地非常多样化&#xff0c;它们常常在人类活动的区域出没&#xff0c;喜欢把鸟巢建在民宅旁边的大树上、旷野的高树上或者电线塔杆上。白天&#xff0c;它们会飞到农田等开阔的地方觅食&#xff0c;到了傍晚则会返回巢内栖息。 喜鹊食性杂&#xff0c;它们的食物组…

2008NOIP普及组真题 4. 立体图

线上OJ&#xff1a; 一本通-1977&#xff1a;【08NOIP普及组】立体图 核心思想&#xff1a; 本题采用模拟方法一个一个画小方块&#xff08;虽然画的是立体空间的积木&#xff0c;但本质还是在二维平面上画图形&#xff09; 本题的难点在于&#xff1a; 1、如何确定二维平面画…