SpringBoot 整合 AOP 实现日志处理原来这么简单? 古城微笑少年丶 2022-12-08 05:19 130阅读 0赞 ### 文章目录 ### * AOP 简述 * SpringBoot 整合 AOP * * Maven 依赖 * 创建日志拦截器 * 完整代码 * 测试 * 相关文章阅读 # AOP 简述 # 相信用过 Spring 的朋友应该都使用过 AOP,AOP 是 (Aspect Oriented Programming 的缩写),意思为**面向切面编程**,通过 预编译方式 和运行期间动态代理 实现程序功能的统一维护的一种技。 AOP 是 OOP(面向对象) 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。 利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的 耦合度 降低,提高程序的可重用性,同时提高了开发效率 # SpringBoot 整合 AOP # ## Maven 依赖 ## <dependency> <!-- 集成 SpringMVC --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 集成 Aspect --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ## 创建日志拦截器 ## 这个日志拦截器主要是使用 AOP 来实现 @Aspect @Component public class LogAspect { } 需要在类上加上 @Aspect 注解,表示这是一个切面类,还需要加上 @Component 注解,可以被扫描到 @Aspect @Component public class LogAspect { /** * 切入点 */ @Pointcut("execution(* com.example.filedemo.controller.*.*(..))") public void log() { } } 定义一个 log() 方法,标上 @Pointcut 注解,表示这是一个切入点,execution() 是最常用的切点函数,其语法如下: * execution():表达式主体 * 第一个 \* 表示返回类型,\* 号 表示所有类型 * 包名:表示需要拦截的包名,后面的两个小数点表示当前包和当前包的所有子包,com.example.filedemo.controller 包以及该包下的子包和所有类的方法 * 第二个 \* 号表示类名,\* 号表示所有的类 * \*(…) 这个星号表示方法名, \* 号表示所有的方法,括号里的小数点表示方法的参数,两个小数点表示任何参数 -------------------- 比如现在我们有这么一个需求,在用户请求时获取用户操作信息,例如:用户访问了哪些内容,URL,输入了什么参数,请求的是哪个方法。我们需要在方法请求前就输出该日志,那么我们应该这么做: @Aspect @Component public class LogAspect { private Logger log = LoggerFactory.getLogger(this.getClass()); /** * 切入点 */ @Pointcut("execution(* com.example.filedemo.controller.*.*(..))") public void log() { } /** * 方法请求前 */ @Before("log()") public void doBefore() { log.info("-------来请求了-------"); } /** * 方法请求后 * 说明:用户请求信息打印 * @param joinPoint 连接点 */ @After("log()") public void doAfter(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String url = request.getRequestURL().toString(); String ip = request.getRemoteAddr(); String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); RequestMethod requestLog = new RequestMethod(url, ip, classMethod, args); log.info("Request : {}", requestLog); } } 可以将用户请求信息封装成一个类 private class RequestMethod { private String url; private String ip; private String classMethod; private Object[] args; public RequestMethod(String url, String ip, String classMethod, Object[] args) { this.url = url; this.ip = ip; this.classMethod = classMethod; this.args = args; } @Override public String toString() { return "RequestMethod{" + "url='" + url + '\'' + ", ip='" + ip + '\'' + ", classMethod='" + classMethod + '\'' + ", args=" + Arrays.toString(args) + '}'; } } 也可以来个方法执行结果输出 /** * 返回执行结果,在执行方法后返回 * pointcut:连接切入点 * returing:返回结果 * @param result */ @AfterReturning(returning = "result", pointcut = "log()") public void doAfterReturn(Object result) { log.info("Result : {}", result); } ## 完整代码 ## package com.example.filedemo.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.util.Arrays; /** * @author Woo_home * @create 2020/9/17 21:04 */ @Aspect @Component public class LogAspect { private Logger log = LoggerFactory.getLogger(this.getClass()); /** * 切入点 */ @Pointcut("execution(* com.example.filedemo.controller.*.*(..))") public void log() { } /** * 方法请求前 */ @Before("log()") public void doBefore() { log.info("-------来请求了-------"); } /** * 方法请求后 * 说明:用户信息打印 * @param joinPoint 连接点 */ @After("log()") public void doAfter(JoinPoint joinPoint) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String url = request.getRequestURL().toString(); String ip = request.getRemoteAddr(); String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); RequestMethod requestLog = new RequestMethod(url, ip, classMethod, args); log.info("Request : {}", requestLog); } /** * 返回执行结果,在执行方法后返回 * @param result */ @AfterReturning(returning = "result", pointcut = "log()") public void doAfterReturn(Object result) { log.info("Result : {}", result); } private class RequestMethod { private String url; // 请求 url private String ip; // 请求 ip private String classMethod; // 请求方法 private Object[] args; // 请求参数 public RequestMethod(String url, String ip, String classMethod, Object[] args) { this.url = url; this.ip = ip; this.classMethod = classMethod; this.args = args; } @Override public String toString() { return "RequestMethod{" + "url='" + url + '\'' + ", ip='" + ip + '\'' + ", classMethod='" + classMethod + '\'' + ", args=" + Arrays.toString(args) + '}'; } } } ## 测试 ## 我们写个简单的 Controller package com.example.filedemo.controller; import com.example.filedemo.util.ResultSet; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap; import java.util.Map; /** * @author Woo_home * @create 2020/9/17 21:42 */ @Controller public class TestController { private Map<String, Object> map = new HashMap<>(); @GetMapping("/info1") @ResponseBody public Map info1() { map.put("1", "zhangsan"); map.put("2", "lisa"); return map; } @GetMapping("/userInfo/{id}/{name}") @ResponseBody public Map userInfo(@PathVariable Integer id, @PathVariable String name) { map.put(String.valueOf(id), name); return map; } } 然后我们将 SpringBoot 跑起来测试一下,首先我们先访问 info1 这个接口 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1dvb19ob21l_size_16_color_FFFFFF_t_70_pic_center] 请求没什么问题,然后我们看下控制台的输出日志 2020-09-18 12:38:24.759 INFO 10192 --- [nio-8080-exec-1] com.example.filedemo.aspect.LogAspect : -------来请求了------- 2020-09-18 12:38:24.933 INFO 10192 --- [nio-8080-exec-1] com.example.filedemo.aspect.LogAspect : Request : RequestMethod{url='http://localhost:8080/info1', ip='0:0:0:0:0:0:0:1', classMethod='com.example.filedemo.controller.TestController.info1', args=[]} 2020-09-18 12:38:24.940 INFO 10192 --- [nio-8080-exec-1] com.example.filedemo.aspect.LogAspect : Result : {1=zhangsan, 2=lisa} > 注意:这里的 ip 0:0:0:0:0:0:0:1 是因为服务器和客户端都在同一台电脑上所以才会出现的 OK,我们再访问 info2 这个接口 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1dvb19ob21l_size_16_color_FFFFFF_t_70_pic_center 1] 请求没什么问题,然后我们看下控制台的输出日志 2020-09-18 12:53:41.438 INFO 12616 --- [nio-8080-exec-1] com.example.filedemo.aspect.LogAspect : -------来请求了------- 2020-09-18 12:53:41.442 INFO 12616 --- [nio-8080-exec-1] com.example.filedemo.aspect.LogAspect : Request : RequestMethod{url='http://localhost:8080/userInfo/100/John', ip='0:0:0:0:0:0:0:1', classMethod='com.example.filedemo.controller.TestController.userInfo', args=[100, John]} 2020-09-18 12:53:41.447 INFO 12616 --- [nio-8080-exec-1] com.example.filedemo.aspect.LogAspect : Result : {100=John} OK,关于 SpringBoot 整合 AOP 的内容就到这了 # 相关文章阅读 # [编写一个接口,实现代理设计模式(Proxy)][Proxy] [Spring的AOP入门(AOP概述、底层实现原理、Cglib、注解)][Spring_AOP_AOP_Cglib] [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1dvb19ob21l_size_16_color_FFFFFF_t_70_pic_center]: /images/20221123/037da36d75aa41d9a897525450f86e20.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1dvb19ob21l_size_16_color_FFFFFF_t_70_pic_center 1]: /images/20221123/fbd3f915aed04340aebe7f57e31b2c33.png [Proxy]: https://blog.csdn.net/Woo_home/article/details/90637026 [Spring_AOP_AOP_Cglib]: https://blog.csdn.net/Woo_home/article/details/89786153
还没有评论,来说两句吧...