首页 > 其他分享 >SpringBoot Aop 日志记录

SpringBoot Aop 日志记录

时间:2023-01-06 14:08:07浏览次数:45  
标签:SpringBoot 连接点 通知 joinPoint 切面 Aop import 日志 方法


文章目录

  • ​​前言​​
  • ​​一、Aop​​
  • ​​1.基本概念​​
  • ​​2.术语理解​​
  • ​​3.通知类型​​
  • ​​二、SpringBoot Aop 整合​​
  • ​​1.引入依赖​​
  • ​​2.注解​​
  • ​​3.切面​​
  • ​​4.使用​​

前言

本文基于Springboot2.x整合Aop时限日志记录

一、Aop

1.基本概念

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming),面向对象编程的补充和完善。面向切面编程是面向对象中的一种方式而已。在代码执行过程中,动态嵌入其他代码,叫做面向切面编程。面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的,与主业务逻辑无关的代码,如安全检查,事物,日志等。若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使业务逻辑变得混杂不清。常见的使用场景:

  • 日志
  • 事物
  • 数据库操作

2.术语理解

target

目标类

需要被代理的类

aspecct

切面

切面泛指交叉业务逻辑。比如事物处理,日志处理就可以理解为切面。常用的切面有通知与顾问。实际就是对主业务逻辑的一种增强

weaving

织入

织入是指将切面代码插入到目标对象的过程

joinpoint

连接点

连接点指切面可以织入的位置

pointcut

切入点

切入点指切面具体织入的位置

advice

通知 增强

通知(Advice)是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。

advisor

顾问

顾问(Advisor)是切面的另一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。不仅指定了切入时间点,还可以指定具体的切入点。

3.通知类型

通知类型

说明

前置通知(MethodBeforeAdvice)

目标方法执行之前调用

后置返回通知(AfterReturningAdvice)

当连接点方法成功执行后,返回通知方法才会执行,如果连接点方法出现异常,则返回通知方法不执行。返回通知方法在目标方法执行成功后才会执行, 所以,返回通知方法可以拿到目标方法(连接点方法)执行后的结果

后置通知(AfterAdvice)

目标方法执行完成之后调用

环绕通知(MethodInterceptor)

目标方法执行前后都会调用方法,且能增强结果

异常处理通知(ThrowsAdvice)

目标方法出现异常调用

二、SpringBoot Aop 整合

1.引入依赖

<!-- AOP依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.注解

package com.dingwen.test.annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/*
@Target:决定了你的注解可以使用的位置
  1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
*/
@Target(ElementType.METHOD)

/*
@Retention :
注解的注解,元注解
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
*/

@Retention(RetentionPolicy.RUNTIME)
public @interface SysLogAnnotation {
// 可以是Object 类型
String value() default "";
}

3.切面

package com.dingwen.test.aspect;

import com.dingwen.test.annotation.SysLogAnnotation;
import com.dingwen.test.entity.SysLog;
import com.dingwen.test.service.SysLogService;
import io.swagger.models.auth.In;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;

/**
* 日志记录切面类
*
* @author dingwen
* 2021.04.27 10:13
*/

// 切面类
@Aspect
// 对象交给Spring管理
@Component
public class SysLogAspect {

// 日志服务
private final SysLogService sysLogService;

@Autowired
SysLogAspect(SysLogService sysLogService){
this.sysLogService = sysLogService;
}
/*
*
* 定义切入点
*/
@Pointcut("@annotation(com.huitian.adapter.ferry.annotation.SysLogAnnotation))")
public void SysLogPointCut() {
}


/*
* 环绕通知
* 切入点指向切入点表达式
* @param proceedingJoinPoint
* @return Object
*/
@Around(value = "SysLogPointCut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) {
Object proceed = null;
// 获取方法签名
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
// 具体方法
Method method = methodSignature.getMethod();
// 方法上的日志切面注解
SysLogAnnotation sysLogAnnotation = method.getAnnotation(SysLogAnnotation.class);
// 注解上面的值 日志类型
Integer logType = getSysLogType(sysLogAnnotation.ferryType());
// 获取请求参数
Object[] args = proceedingJoinPoint.getArgs();

try {
proceed = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
sysLogService.save(sysLog);
return proceed;
}

/*
前置通知
*/
@Before(value = "SysLogPointCut()")
public void before(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert attributes != null;
HttpServletRequest request = attributes.getRequest();
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("调用前连接点方法为:" + methodName + ",参数为:" + args);
System.out.println("前置通知");
}

/*
* 返回通知
* 当连接点方法成功执行后,返回通知方法才会执行,
* 如果连接点方法出现异常,则返回通知方法不执行。返回通知方法在目标方法执行成功后才会执行,
* 所以,返回通知方法可以拿到目标方法(连接点方法)执行后的结果
* @param joinPoint 连接点
* @param result 就是response
*
*/
@AfterReturning(pointcut = "SysLogPointCut()",returning = "result")
public void afterReturn(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("连接点方法为:" + methodName + ",参数为:" + args + ",目标方法执行结果为:" + result);
}

/*
后置通知
*/
@After(value = "SysLogPointCut()")
public void after(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("调用后连接点方法为:" + methodName + ",参数为:" + args);
}
/*
后置返回通知
*/
@AfterThrowing(value = "SysLogPointCut()",throwing = "exception")
public void afterThrowing(JoinPoint joinPoint,Exception exception){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("连接点方法为:" + methodName + ",参数为:" + args + ",异常为:" + exception);
}
}

4.使用

/*
* 登录
* @return Result
*/
@PostMapping("/login")
@SysLogAnnotation(value= "登录")
public Result sendTextMsg(HttpServletRquest request,
@RequestBody User user) {
return ResultGenerator.genOkResult();
}



标签:SpringBoot,连接点,通知,joinPoint,切面,Aop,import,日志,方法
From: https://blog.51cto.com/u_15932195/5993195

相关文章

  • Spring之AOP
    AOP是什么?AOP:在软件业,AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软......
  • mysql8.0设置binlog保存时间,并清除过期日志释放空间
    在线修改mysql>showvariableslike'%expire%';+--------------------------------+---------+|Variable_name|Value|+-------------------------......
  • SqlServer日志增长过快应对策略
    原文链接:https://www.jianshu.com/p/f59e41a2ea5ehttps://www.modb.pro/db/42341https://blog.csdn.net/cuiweigk19423/article/details/100464016/问题排查过程:输入查......
  • Springboot整合策略模式概念->使用场景->优缺点->企业级实战
    一、前言策略模式可能是在工作中使用最多的,也是在面试中最常提到的,代码重构和优化的必备!小编之前也是一直说,其实没有真正的实战;最近有了机会实战了一下,来分享一下使用心......
  • sql日志:获得数据库报错信息
    原文链接:https://jingyan.baidu.com/article/25648fc1a6d0d5d090fd0024.html1、选择资源管理器下的“管理”选项卡,点击“sqlserver”日志 2、选择对话框中,双击相应的......
  • SpringBoot过滤器/拦截器
    不同点项过滤器拦截器使用场景对请求/响应进行修改、判断等。一般用于过滤参数、登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换。在service或者一个方法前......
  • springboot使用redis实现计数限流
    lua脚本resources下创建文件redis/AccessLimit.lua内容为:locallimitSecond=tonumber(ARGV[1])locallimitMaxCount=tonumber(ARGV[2])localnum=tonumber(......
  • 如何跳出springboot的service层中某一个方法?
    有一个需求,就是中断某个方法中的for循环目前的做法是:for循环中,增加if判断,如果满足条件就return,会中断这个方法for(inti=0;i<totalIndex;i++){............
  • 情绪日志-2023-01
    0105情绪处理【解决】看了几部影片解说之后,四点半睡觉,中午之前起床。当时的情绪是什么?害怕关掉平板,害怕黑灯瞎火的躺在床上想着种种往事,想用视频麻痹自己不去想让自己痛......
  • SpringBoot整合Caffeine(通过注解)
    一、了解缓存配置先来了解一下配置方法吧,SimpleCacheManager和CaffeineCacheManager配置的区别:SimpleCacheManager: 这种缓存管理器允许你在应用程序启动时通过配置......