SpringBoot实现SpringAop,AOP实现日志

2024-04-16 15:38

本文主要是介绍SpringBoot实现SpringAop,AOP实现日志,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

B站视频地址


关于什么是AOP,AOP用来做什么,AOP里面的两种代理这里都不做讨论。本文只是在应用的层面去讲解AOP


一、关于AOP里面的一些概念

  • Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点
  • Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
  • Advice(通知):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  • Aspect(切面): 是切入点和通知(引介)的结合
  • Target(目标对象):代理的目标对象(要增强的类)
  • Weaving(织入): 是把增强应用到目标的过程,把advice 应用到 target的过程
  • Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

  • Before(前置通知):在目标方法之前执行
  • After(后置通知):在目标方法之后执行(不管目标方法是否执行成功都会执行)
  • AfterReturning(正常后置通知):目标方法正常执行结束后执行
  • AfterThrowing(异常后置通知):目标方法异常后执行
  • Around(环绕通知):目标方法执行前后都执行

二、Demo搭建

 <!-- spring-boot-starter-aop --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.2.0.RELEASE</version></dependency>

2-1、切面定义

@Aspect
@Component
public class LogAspect {}

2-2、Pointcut定义

也就是我们要对那些方法进行AOP处理


2-2-1、使用匹配方式

就是配置我们要把哪些包下面的方法进行AOP拦截了。

下面这个就是对com.koron.workorder包下面的servlet包下面的类全部进行拦截

具体的配置百度一下SpringAOP切点配置就行

private static final String POINT_CUT_INCLUDE = "execution(public * com.koron.workorder..servlet.*.*(..))";@Pointcut(POINT_CUT_INCLUDE)
public void controllerLog() {
}

2-2-2、注解方式拦截

在方法上面使用了这个注解就会被AOP拦截

自定义注解

这个注解里面有三个参数,当然了这个是自定义的,你想要几个完全根据业务来定义即可

import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogDefined {String operate() default "";String module() default "";String desc() default "";
}

pointCut书写

@Pointcut("@annotation(com.xdx97.mianshiba.common.aop.log.LogDefined)")
public void controllerLog() {
}

2-3、advice通知


2-3-1、前置通知(Before)

在执行目标方法之前执行

// 前置通知
@Before("controllerLog()")
public void logBefore(JoinPoint joinPoint){System.out.println("before");
}

2-3-2、后置通知(After)

在目标方法之后执行(不管目标方法是否执行成功都会执行)

@After("controllerLog()")
public void logAfter(JoinPoint point){System.out.println("after");
}

2-3-3、正常后置通知(AfterReturning)

目标方法正常执行结束后执行,result是目标方法返回的结果

@AfterReturning(pointcut = "controllerLog()", returning = "result")
public void logAfterReturning(JoinPoint point,String result){System.out.println("result = " + result);System.out.println("logAfterReturning");
}

2-3-4、异常后置通知(AfterThrowing)

目标方法异常后执行

@AfterThrowing("controllerLog()")
public void logAfterThrowing(JoinPoint point){System.out.println("logAfterThrowing");
}

2-3-5、环绕通知(Around)

目标方法执行前后都执行

@Around("controllerLog()")
public Object logAround(ProceedingJoinPoint point) throws Throwable {System.out.println("目标方法执行前...");Object proceed = point.proceed();System.out.println("目标方法执行后...");return proceed;
}
point.proceed();

这句代码,就是去执行目标方法, proceed 是目标方法的返回值。


2-3-6、其它

我们看到每一个通知方法里面都有JoinPoint参数,我们可以从里面获取数据,比如获取请求的参数

Object[] args = joinPoint.getArgs();
for (Object item : args){System.out.println(item);
}

2-3-7、测试

TestController

import com.xdx97.mianshiba.common.aop.log.LogDefined;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class TestController {@GetMapping("/test")@LogDefined(operate = "测试",module = "测试模块",desc="简单描述")public String fun(@RequestParam String str){System.out.println("active" + str);return "success";}
}

执行结果

http://127.0.0.1:8888/test?str=31231

目标方法执行前...
31231
before
active31231
目标方法执行后...
after
result = success
logAfterReturning

完整的切面

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LogAspect {@Pointcut("@annotation(com.xdx97.mianshiba.common.aop.log.LogDefined)")public void controllerLog() {}// 前置通知@Before("controllerLog()")public void logBefore(JoinPoint joinPoint){Object[] args = joinPoint.getArgs();for (Object item : args){System.out.println(item);}System.out.println("before");}// 后置通知 不管异常不异常都会执行@After("controllerLog()")public void logAfter(JoinPoint point){System.out.println("after");}// 返回通知--当代码运行正常后执行@AfterReturning(pointcut = "controllerLog()", returning = "result")public void logAfterReturning(JoinPoint point,String result){System.out.println("result = " + result);System.out.println("logAfterReturning");}// 异常通知 -- 发送异常后执行@AfterThrowing("controllerLog()")public void logAfterThrowing(JoinPoint point){System.out.println("logAfterThrowing");}// 环绕通知@Around("controllerLog()")public Object logAround(ProceedingJoinPoint point) throws Throwable {System.out.println("目标方法执行前...");Object proceed = point.proceed();System.out.println("目标方法执行后...");return proceed;}
}

三、实现log

import com.xdx97.mianshiba.bean.pojo.common.BUser;
import com.xdx97.mianshiba.common.utils.RedisUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;@Aspect
@Component
public class LogAspect {@Pointcut("@annotation(com.xdx97.mianshiba.common.aop.log.LogDefined)")public void controllerLog() {}// 返回通知--当代码运行正常后执行@AfterReturning(pointcut = "controllerLog()", returning = "result")public void logAfterReturning(JoinPoint point,String result){// 1、从request里面获取tokenServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = servletRequestAttributes.getRequest();String token = request.getHeader("token");// 2、使用token从Redis里面获取用户信息BUser user = (BUser)RedisUtils.get(token);Map<String,Object> map = new HashMap<>();map.put("userId",user.getId());map.put("userName", user.getUserName());// 3、获取拦截的参数MethodSignature signature = (MethodSignature) point.getSignature();//从切面织入点处通过反射机制获取织入点处的方法Method logMethod = signature.getMethod();//获取切入点所在的方法LogDefined logDefined = logMethod.getAnnotation(LogDefined.class); //获取操作if (logDefined != null) { //记录操作信息try {map.put("operate",logDefined.operate());map.put("module",logDefined.module());map.put("desc",logDefined.desc());} catch (Exception e) {throw new RuntimeException("操作日志字段名填写有误");}}// 4、把数据插入数据库  map}
}

四、其它

4-1、AOP执行顺序

我们可以在切面上加入 @Order(1) 注解,里面的数值越小,执行顺序越前。

这篇关于SpringBoot实现SpringAop,AOP实现日志的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/909205

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

C#实现一键批量合并PDF文档

《C#实现一键批量合并PDF文档》这篇文章主要为大家详细介绍了如何使用C#实现一键批量合并PDF文档功能,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言效果展示功能实现1、添加文件2、文件分组(书签)3、定义页码范围4、自定义显示5、定义页面尺寸6、PDF批量合并7、其他方法

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2