Springboot 自定义注解+AOP简单实例介绍

Springboot 自定义注解+AOP简单实例介绍这个 AOP 使用分享里 结合用到的还有自定义注解做切点 环绕增强拦截方法 请求参的截取 我们先了解下 AOP 已经知道的 直接往后拖 AOP 面向切面编程 OOP 面向对象编程 个人鄙见 在 OOP 模式编程的时候 有时候很多的对象都需要添加一些公共的行为的时候 也许你会想到继承啊 提抽象啊 实现接口啊等等 没错 这是给很多对象添加公共行为的一个表现 其实就是多态嘛 但是这种

前言:

该篇以记录接口调用的传入参数日志为场景,来介绍下使用自定义注解作为切点,AOP切面方式去记录每个接口的传入参数以及可扩展的业务处理。

 

正文:

项目目录:

Springboot 自定义注解+AOP简单实例介绍

 

先是创建自定义注解, LogTrack:

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; / * @Author : JCccc * @CreateTime : 2020/4/13 * @Description : / @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface LogTrack { String value() default "logTracking"; } 

上面的自定义注解,我只用了一个默认参,所以不用命名,写value就可以。

 

然后写切点对应的代码,LogTrackAspect:

 
   
   
   
     com.alibaba 
    
   
     fastjson 
    
   
     1.2.58 
    
  

 

/ * @Author : JCccc * @CreateTime : 2020/4/13 * @Description : / @Component @Aspect public class LogTrackAspect { private static final Logger log = LoggerFactory.getLogger(LogTrackAspect.class); //这里需要注意了,这个是将自己自定义注解作为切点的根据,路径一定要写正确了 @Pointcut(value = "@annotation(com.jc.mytest.aop.logRecord.LogTrack)") public void access() { } //进来切点世界,先经过的第一个站 @Before("access()") public void doBefore(JoinPoint joinPoint) throws Throwable { System.out.println("-aop 日志记录启动-" + new Date()); } //环绕增强,是在before前就会触发 @Around("@annotation(logTrack)") public Object around(ProceedingJoinPoint pjp, LogTrack logTrack) throws Throwable { System.out.println("-aop 日志环绕阶段-" + new Date()); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // GET 请求其实可以从request里获取出参数 // Map 
  
    map=request.getParameterMap(); // System.out.println("获取参数:"+map.get("username")[0]) String url = request.getRequestURL().toString(); String ip = IpUtil.getIpAddr(request); String logTrackValue = logTrack.value(); Object[] pipArrary = pjp.getArgs(); if (pipArrary.length>1){ //多参,不是Map/JsonObject方式 List 
    argList = new ArrayList<>(); for (Object arg : pjp.getArgs()) { // request/response无法使用toJSON if (arg instanceof HttpServletRequest) { argList.add("request"); } else if (arg instanceof HttpServletResponse) { argList.add("response"); } else { argList.add(JSON.toJSON(arg)); } } Signature signature = pjp.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; // 参数名数组 String[] parameterNames = ((MethodSignature) signature).getParameterNames(); System.out.println("参数名数组:"+new ArrayList(Arrays.asList(parameterNames))); System.out.println("参数是:"+argList.toString()); System.out.println("logTrackValue:"+logTrackValue); System.out.println("url:"+url); System.out.println("ip:"+ip); return pjp.proceed(); } Object param = pipArrary[0]; System.out.println("logTrackValue:"+logTrackValue); System.out.println("url:"+url); System.out.println("ip:"+ip); System.out.println("param:"+param.toString()); return pjp.proceed(); } //进来切点这,最后经过的一个站,也是方法正常运行结束后 @After("access()") public void after(JoinPoint joinPoint) { System.out.println("-aop 日志记录结束-" + new Date()); } }  
  

ps:return pjp.proceed(); 这个是从切点的环绕增强里面脱离出来,接下来会进入before阶段 ,然后回到接口,再回来after阶段。

所以扩展业务逻辑处理的话,可以放在return pjp.proceed();这行代码之前,例如判断用户密码是否正确;判断用户权限等等。

 

接下来是在Controller编写接口,并用上自定义注解,MyTestController:

/ * @Author : JCccc * @CreateTime : 2020/3/27 * @Description : / @Controller @RequestMapping("/test") public class MyTestController { @ResponseBody @GetMapping("/testGet1") @LogTrack("testGet1 接口") public void testGet1(@RequestParam("userId") String userId, @RequestParam("toUserId") String toUserId) { System.out.println("已经进入GET测试接口,参数userId:" + userId+ "参数toUserId:"+toUserId); } @ResponseBody @GetMapping("/testGet2") @LogTrack("testGet2 接口") public void testGet2(@RequestParam Map map) { System.out.println("已经进入GET测试接口,参数:" + map.get("userId")); } @ResponseBody @PostMapping("/testPost1") @LogTrack("testPost1 接口") public void testPost1(@RequestBody Map map) { System.out.println("已经进入POST测试接口,参数:" + map.toString()); } @ResponseBody @PostMapping("/testPost2") @LogTrack("testPost2 接口") public void testPost2(@RequestBody JSONObject jsonObject) { System.out.println("已经进入POST测试接口,参数:" + jsonObject.toString()); } }

然后我们来运行一下,看看控制台,就知道整个切点以及环绕的流程了: 

 

调用接口:

Springboot 自定义注解+AOP简单实例介绍

运行结果:

 Springboot 自定义注解+AOP简单实例介绍

 

接下来还是GET方式 ,通过Map去接收多参:

Springboot 自定义注解+AOP简单实例介绍

调用接口:

Springboot 自定义注解+AOP简单实例介绍

运行结果:

Springboot 自定义注解+AOP简单实例介绍

 

然后是调用Post请求:

Springboot 自定义注解+AOP简单实例介绍

 

Springboot 自定义注解+AOP简单实例介绍

 

1.检查jar包是否有导入正确

 
   
   
     org.aspectj 
    
   
     aspectjweaver 
    
   
     1.9.4 
    
   
   
   
     org.aspectj 
    
   
     aspectjrt 
    
   
     1.8.9 
    
  

 

 

 

本篇使用到的一些工具类:

IpUtil:

import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; / * @Author : JCccc * @CreateTime : 2018-11-23 * @Description : * @Point: Keep a good mood / public class IpUtil { public static String getIpAddr(HttpServletRequest request) { String ipAddress = null; try { ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (ipAddress.equals("127.0.0.1")) { // 根据网卡取本机配置的IP InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ipAddress = inet.getHostAddress(); } } // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ipAddress != null && ipAddress.length() > 15) { // "*.*.*.*".length() // = 15 if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } } catch (Exception e) { ipAddress=""; } // ipAddress = this.getRequest().getRemoteAddr(); return ipAddress; } } 

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204766.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午7:35
下一篇 2026年3月19日 下午7:35


相关推荐

  • Centos 7 配置阿里云yum源

    Centos 7 配置阿里云yum源Centos7 配置阿里云 yum 源原因 有的时候服务器需要下载一些软件 是本地 yum 源没有的 这时候需要配置网络 yum 源 阿里云 yum 源 1 通过远程工具 Xshell 连接 Linux2 进入目录 cd etc yum repos d 3 备份原镜像文件 以免出错后可以恢复 4 下载新的 CentOS Base repo 到 etc yum repos d 命令 wget

    2026年3月16日
    3
  • 捣鼓PlantUML(三、时序图)

    捣鼓PlantUML(三、时序图)简单介绍时序图 SequenceDiag 又名序列图 循序图 顺序图 是一种 UML 交互图 它通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作 它可以表示用例的行为顺序 当执行一个用例行为时 其中的每条消息对应一个类操作或状态机中引起转换的触发事件 PlantUML 使用 箭头将一条消息连接两个对象 参与者 对象本身不需要特别声明 如果想使用虚线箭头 则使用 箭头方向调转

    2026年3月17日
    4
  • 扫描系统漏洞的工具_免费漏洞扫描工具

    扫描系统漏洞的工具_免费漏洞扫描工具端口扫描之王NMAPNmap是一款非常强大的实用工具包含的功能如下:扫描到的端口状态:TCP扫描(-sT):这是一种最为普通的扫描方法,这种扫描方法的特点是:扫描的速度快,准确性高,对操作者没有权限上的要求,但是容易被防火墙和IDS(防入侵系统)发现运行的原理:通过建立TCP的三次握手连接来进行信息的传递SYN扫描(-sS):这是一种秘密的扫描方式之一,因为在SYN扫描中Client端和Server端没有形成3次握手,所以没有建立一个正常的TCP连接,因此不被防火墙和日志所记录…

    2025年11月3日
    8
  • Pycharm unresolved reference问题

    Pycharm unresolved reference问题使用 Pycharm 编辑 py 代码时 偶会发现提示 unresolvedre cannotfindre 等信息 出现这个提示也许不会影响正常运行 但看着红波浪线就别扭 这个原因是由于 python 第三方库没有同步至最新版本导致的 可以在 settings 里查看有哪些可用更新并更新 也可以直接用 pip 命令查看更新信息 piplist

    2026年3月20日
    3
  • 软件过程改进纪实—从CVS到UnitTest再到Bugzilla

    软件过程改进纪实—从CVS到UnitTest再到Bugzilla

    2021年8月25日
    57
  • XBox360自制系统的更新(Update)「建议收藏」

    XBox360自制系统的更新(Update)「建议收藏」升级了XBox360自制系统之后,还需要进一步更新系统来解决黑白人偶和无法使用Kinect的问题。

    2022年8月2日
    46

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号