当前位置: 首页 > news >正文

【Java】自定义注解和AOP切面的使用

前言

我们在开发的过程中,一般都需要对方法的入参进行打印,或者Debug调试的时候我们要查看方法入参的参数是否数量和数据正确性。

一般我们需要知道请求的参数接口路径请求ip

但是考虑以后项目上线BUG排查的问题,最好的方式就是使用切面的方式来记录每个方法执行时要保存的日志处理,那么下面我们来实现一个使用自定义注解的方式来对每个请求的方法上进行日志存储

AOP切面:对某个方法进行增强处理,例如在某个方法执行前或者执行后进行操作。

案例

首先我们看一个controller接口

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping("/user/")
public class TestController {

    @PostMapping("getUserById")
    public String getUserById(@RequestBody User user) {
        log.info("/user/getUserById params:{}", user.toString());
        //执行代码逻辑...
        return "请求成功";
    }
}

这种一般没什么问题,一般我们测试的时候都可以这样来写,但如果有很多的方法,那么每个方法都这样写,显然很是繁琐,那么我们通过下面的方式来实现当进入方法前打印请求的一些信息

实现

我们自定义一个注解,名为Itboy

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)//ElementType.METHOD表示为该注解在方法上添加
public @interface Itboy {
}

然后需要用到一些依赖,这些是使用AOP的依赖,我们提前引入一下

<dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.14</version>
</dependency>
<dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.9.19</version>
</dependency>

然后我们定义一个切面类,名为ItboyAspect
注:这篇文章我使用的System打印方式,如果需要保存日志,换为对应的logger.info()即可。

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
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.text.SimpleDateFormat;
import java.util.Date;

@Component
@Aspect
@Slf4j
public class ItboyAspect {
    //@Pointcut:为切入点,切入到Itboy这个注解上面
    @Pointcut("@annotation(com.mayikt.demo.Itboy)")
    public void itboyAspect() {}

    //@Before为在进入切点之前自动执行Before中的逻辑(进入之前的前提是方法上需要有我们设置的自定注解)
    @Before("itboyAspect()")
    public void beforeItboy(JoinPoint joinPoint) {
        //获取本次请求
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //获取到方法名
        String methodName = joinPoint.getSignature().getName();
        System.err.println("======================================方法:" + methodName + "() 开始======================================");
        //执行时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        String time = sdf.format(date);
        System.err.println("时间                 : " + time);
        //请求URL
        System.err.println("URL                 : " + request.getRequestURL());
        //请求方法
        System.err.println("HTTP Method         : " + methodName);
        //打印controller全路径和执行方法
        System.err.println("Class Method        : " + joinPoint.getSignature().getDeclaringTypeName() + "." + methodName);
        //请求IP
        System.err.println("IP                  : " + request.getRemoteHost());
        //请求入参
        System.err.println("Requert params      : " + JSON.toJSONString(joinPoint.getArgs()));
    }
	
	//后置通知
	@After("itboyAspect()")
    public void afterItboy(JoinPoint joinPoint) {
        //获取到方法名
        String methodName = joinPoint.getSignature().getName();
        System.err.println("======================================方法:" + methodName + "() 结束======================================");
    }
}

然后我们只需要在需要保存的方法上添加@Itboy注解即可

	@Itboy
    @PostMapping("selectUserList")
    public String getUserById(@RequestBody User user) {
        log.info("/user/selectUserList params:{}", user.toString());

        //执行代码逻辑...
        return "请求成功";
    }

最后我们来看一下效果

2023-04-02 14:21:29.033  INFO 5912 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
======================================方法:getUserById() 开始======================================
时间                 : 2023-04-02 14:21:29
URL                 : http://127.0.0.1:8080/user/selectUserList
HTTP Method         : getUserById
Class Method        : com.mayikt.demo.TestController.getUserById
IP                  : 127.0.0.1
Requert params      : [{"address":"华东","age":18,"id":10010,"name":"贾强"}]
======================================方法:getUserById() 结束======================================
2023-04-02 14:21:29.171  INFO 5912 --- [nio-8080-exec-1] com.mayikt.demo.TestController           : /user/selectUserList params:User(id=10010, name=贾强, age=18, address=华东)

总结

使用上面这种方式,减轻了我们自己手动日志打印的繁琐,而且配置也相对于比较简单,如果有其他需求是比较频繁的操作的话,我们就可以使用AOP切面的方式来完成。

肥肠好用

相关文章:

  • 论文心得笔记
  • 等保部作业
  • ASIC-WORLD Verilog(3)第一个Verilog代码
  • jquery基础之效果
  • 爬虫-day1-正则表达式作业
  • 【SSM】Spring6(一.IOC的实现)
  • vue开发常用的工具有哪些
  • 使用Selenium和Chrome浏览器获取诗词网站搜索结果
  • C++STL 标准模板库
  • chatGDP一下火爆全球,李开复宣布亲自筹组 Project AI 2.0,做中文版的chatGDP,Android程序员的前景还有多少可能?
  • Python for while 循环
  • 【Linux】理解Linux中硬链接和软链接
  • 【Java EE】-多线程编程(四) 死锁
  • 音段特征 VS 超音段特征
  • 基于Python长时间序列遥感数据处理及在全球变化、物候提取、植被变绿与固碳分析、生物量估算与趋势分析等领域中的应用实践技术
  • 【高级语言程序设计】第 6 章:函数
  • 国内较好的erp企业有哪些?
  • JavaScript核心高级内容复习3
  • 硬盘坏了?有了量子计算机,还要修硬盘吗?
  • 类和对象-下
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉