• springboot整合aop,实现日志操作


    前言:

    整合之前,我们要明白aop是什么,为什么要用aop,aop能帮我们做什么。

    答:AOP是面向切面编程(Aspect-Oriented Programming)的简称,它是一种编程思想,旨在在面向对象编程(OOP)的基础上进行功能模块的解耦和隔离。在传统的业务处理代码中,通常需要进行事务处理日志记录等操作,这些操作会分散到各个方法中,增加了开发和维护的难度。AOP通过预编译方式和运行期动态代理实现,在不修改源代码的情况下,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。

    因此,AOP能够帮我们做以下事情:

    1. 降低业务逻辑的耦合性,提高程序的可重用型和开发效率。
    2. 对业务逻辑的各个部分进行隔离,便于模块化管理。
    3. 提取公共功能,减少重复代码,提高代码的可维护性和可读性。
    4. 提供一种新的编程视角和工具,使开发人员可以专注于业务逻辑的实现,而不用过多关注其他功能的实现。

    AOP能够提高开发效率和代码质量,降低维护成本。

    =========================================================================

    一、AOP介绍

    1、名词介绍

    (1)切面(Aspect):切入点和通知的集合
    (2)连接点(Joinpoint):目标对象中可以被增强的所有方法
    (3)通知(Advice):增强的代码(逻辑),分为前置,后置,最终,异常,环绕
    (4)切入点(Pointcut):目标对象中经过匹配最终增强的方法
    (5)引入(Introduction):动态的为某个类增加和减少方法
    (6)目标对象(Target Object):被代理的对象
    (7)AOP代理对象(AOP Proxy):AOP框架创建的代理对象,用于实现切面,调用方法
    (8)织入(Weaving):将通知应用到切入点的过程

    2、注解介绍

    (1)@EnableAspectJautoProxy 用于springboot启动类,代表开启注解aop功能支持
                    proxyTargetClass 是否强制使用CGlib的动态代理,默认false
                    exposeProxy 是否通过aop框架暴露该代理对象,aopContext能够访问
    (2)@Aspect 用于标注切面类
    (3)@Pointcut 用于标识切入点
                    value 切入点表达式
    (4) @Before 前置通知
    (5)@AfterReturning 后置通知
    (6)@AfterThrowing 异常通知
    (7)@After 最终通知
    (8)@Around 环绕通知,环绕通知代表了一个完整的流程,因此环绕通知和上面的四个通知任选其一使用

    3、切入点表达式

    (1)execution - 根据表达式匹配,使用最多

            execution([修饰符] 返回类型 [包名.类名].方法名(参数列表) [异常])

            支持的通配符有 *:匹配所有。..:匹配多级包或者多个参数。+表示类以及子类

    (2)within - 匹配方法所在的包或者类

    (3)this - 用于向通知方法中传入代理对象的引用

    (4)target - 用于向通知方法中传入目标对象的引用

    (5)args - 用于向通知方法中传入参数,并且匹配参数个数

    (6)@args - 和args都是匹配参数,但是@args要求传入切入点的参数必须标注指定注解,且不能是SOURCE源码注解,比如Lombok的

    (7)@within - 匹配加了某个注解的类中的所有方法

    (8)@target - 与@within类似,但是要求标注到类上的注解,必须为RUNTIME的

    (9)@annotation - 匹配加了某个注解的方法

    (10)bean 通过spring容器中的beName匹配

            可以使用通配符*来标识以什么开头,以什么结尾

    二、整合AOP实现,实现日志操作

    1、引入依赖

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-aopartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>com.alibabagroupId>
    7. <artifactId>fastjsonartifactId>
    8. <version>2.0.32version>
    9. dependency>

    2、类

    1. package com.mgx.demo.common.enums;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Getter;
    4. /**
    5. * @author mgx
    6. */
    7. @AllArgsConstructor
    8. @Getter
    9. public enum CharacterEnum {
    10. /**
    11. * 特殊字符
    12. */
    13. //空白
    14. BLANK("")
    15. //空格
    16. , SPACE(" ")
    17. //换行
    18. , NEWLINE("\n")
    19. //enter换行
    20. , ENTER("\r")
    21. //左斜杠
    22. , SLASH("/")
    23. //双左斜杠
    24. , DOUBLE_SLASH("//")
    25. //反斜杠
    26. , BACKSLASH("\\")
    27. //单引号
    28. , QUOTES("'")
    29. //双引号
    30. , DOUBLE_QUOTES("\"")
    31. //撇号
    32. , APOSTROPHE("`")
    33. //艾特符
    34. , AT("@")
    35. //井号
    36. , HASHTAG("#")
    37. //dollar符
    38. , DOLLAR("$")
    39. //百分号
    40. , PERCENT("%")
    41. //异或运算符 数字相同返回0,否则为1
    42. , XOR("^")
    43. //and符
    44. , AND("&")
    45. //星号
    46. , ASTERISK("*")
    47. //等于号
    48. , EQUAL("=")
    49. //下划线
    50. , UNDERSCORE("_")
    51. //点
    52. , DOT(".")
    53. //句号
    54. , C_DOT("。")
    55. //逗号
    56. , COMMA(",")
    57. //中文逗号
    58. , C_COMMA(",")
    59. //管道符
    60. , PIPE("|")
    61. //双管道符
    62. , DOUBLE_PIPE("||")
    63. //问号
    64. , Q_MARK("?")
    65. //叹号
    66. , E_MARK("!")
    67. //加号
    68. , PLUS("+")
    69. //连字号、短横杠、减号
    70. , HYPHEN("-")
    71. //小于符
    72. , LT("<")
    73. //大于符
    74. , GT(">")
    75. //冒号
    76. , COLON(":")
    77. //分号
    78. , SEMICOLON(";")
    79. //中文分号
    80. , C_SEMICOLON(";")
    81. //左圆括号 round
    82. , L_R_BRACKETS("(")
    83. //右圆括号
    84. , R_R_BRACKETS(")")
    85. //左右圆括号
    86. , R_BRACKETS("()")
    87. //左方括号 square
    88. , L_S_BRACKETS("[")
    89. //右方括号
    90. , R_S_BRACKETS("]")
    91. //左右方括号
    92. , S_BRACKETS("[]")
    93. //左大括号 curly
    94. , L_C_BRACKETS("{")
    95. //右大括号
    96. , R_C_BRACKETS("{")
    97. //左右大括号
    98. , C_BRACKETS("{}")
    99. ;
    100. private final String character;
    101. public String value() {
    102. return character;
    103. }
    104. }
    1. package com.mgx.demo.utils;
    2. import com.alibaba.fastjson.JSON;
    3. import com.mgx.demo.common.enums.CharacterEnum;
    4. import lombok.extern.slf4j.Slf4j;
    5. import org.springframework.web.context.request.RequestAttributes;
    6. import org.springframework.web.context.request.RequestContextHolder;
    7. import org.springframework.web.context.request.ServletRequestAttributes;
    8. import javax.servlet.http.HttpServletRequest;
    9. import java.util.Arrays;
    10. import java.util.Objects;
    11. /**
    12. * @author mgx
    13. */
    14. @Slf4j
    15. public class LogUtil {
    16. /**
    17. * 接口请求日志
    18. *
    19. * @param param 接口获取参数
    20. */
    21. public static void param(Object... param) {
    22. RequestAttributes ra = RequestContextHolder.getRequestAttributes();
    23. ServletRequestAttributes sra = (ServletRequestAttributes) ra;
    24. if (Objects.nonNull(sra)) {
    25. HttpServletRequest request = sra.getRequest();
    26. String url = request.getRequestURL().toString();
    27. log.info("===============++++请求++++================\n地址:{}\n参数:{}", url, Objects.isNull(param) ? CharacterEnum.BLANK.value() : Arrays.toString(param));
    28. }
    29. }
    30. /**
    31. * 接口请求日志
    32. *
    33. * @param param 封装后的参数,若数据结构较复杂,请考虑json转化string耗时及性能
    34. */
    35. public static void paramObject(Object param) {
    36. RequestAttributes ra = RequestContextHolder.getRequestAttributes();
    37. ServletRequestAttributes sra = (ServletRequestAttributes) ra;
    38. if (Objects.nonNull(sra)) {
    39. HttpServletRequest request = sra.getRequest();
    40. String url = request.getRequestURL().toString();
    41. log.info("===============++++请求++++================\n地址:{}\n参数:{}", url, Objects.isNull(param) ? CharacterEnum.BLANK.value() : JSON.toJSONString(param));
    42. }
    43. }
    44. public static void logRequest(HttpServletRequest request) {
    45. log.info("===============++++请求++++================\n地址:{}\n方法:{}\nIP:{}", request.getRequestURL().toString(), request.getMethod(), request.getRemoteAddr());
    46. }
    47. }
    1. package com.mgx.demo.config.aop;
    2. import com.alibaba.fastjson.JSON;
    3. import com.mgx.demo.annotation.LogRequestParam;
    4. import com.mgx.demo.utils.LogUtil;
    5. import org.aspectj.lang.JoinPoint;
    6. import org.aspectj.lang.annotation.AfterReturning;
    7. import org.aspectj.lang.annotation.Aspect;
    8. import org.aspectj.lang.annotation.Before;
    9. import org.aspectj.lang.annotation.Pointcut;
    10. import org.slf4j.Logger;
    11. import org.slf4j.LoggerFactory;
    12. import org.springframework.stereotype.Component;
    13. /**
    14. * 自动打印日志
    15. */
    16. @Aspect
    17. @Component
    18. public class WebLogAspect {
    19. private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
    20. @Pointcut("execution(public * com.mgx.demo.controller.*.*(..))")
    21. public void webLog() {}
    22. @AfterReturning(returning = "ret", pointcut = "webLog()")
    23. public void doAfterReturning(Object ret) {
    24. // 处理完请求,返回内容
    25. logger.info("RESPONSE : {}", JSON.toJSONString(ret));
    26. }
    27. @Before("@annotation(logRequestParam) || @within(logRequestParam)")
    28. public void doRequestParamLog(JoinPoint joinPoint, LogRequestParam logRequestParam) {
    29. // 获取方法参数
    30. Object[] args = joinPoint.getArgs();
    31. if (args != null) {
    32. if (args.length == 1) {
    33. LogUtil.paramObject(args[0]);
    34. } else {
    35. LogUtil.param(args);
    36. }
    37. }
    38. }
    39. }
    1. package com.mgx.demo.annotation;
    2. import java.lang.annotation.ElementType;
    3. import java.lang.annotation.Retention;
    4. import java.lang.annotation.RetentionPolicy;
    5. import java.lang.annotation.Target;
    6. /**
    7. * @author mgx
    8. */
    9. @Target({ElementType.TYPE, ElementType.METHOD})
    10. @Retention(RetentionPolicy.RUNTIME)
    11. public @interface LogRequestParam {
    12. }
    1. "1.0" encoding="UTF-8"?>
    2. <configuration>
    3. <springProperty scope="context" name="logPath" source="project.log.config" defaultValue="${user.home}/springboot-mgx/logs"/>
    4. <property name="LOG_HOME" value="${logPath}"/>
    5. <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    6. <encoder>
    7. <pattern>%date{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) (%file:%line\)- %m%npattern>
    8. <charset>UTF-8charset>
    9. encoder>
    10. appender>
    11. <appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
    12. <File>${LOG_HOME}/sys.logFile>
    13. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    14. <fileNamePattern>${LOG_HOME}/%d{yyyy-MM/dd/HH}/sys.%i.logfileNamePattern>
    15. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
    16. <maxFileSize>30MBmaxFileSize>
    17. timeBasedFileNamingAndTriggeringPolicy>
    18. rollingPolicy>
    19. <encoder>
    20. <pattern>%d %p (%file:%line\)- %m%npattern>
    21. <charset>UTF-8charset>
    22. encoder>
    23. appender>
    24. <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
    25. <filter class="ch.qos.logback.classic.filter.LevelFilter">
    26. <level>ERRORlevel>
    27. <onMatch>ACCEPTonMatch>
    28. <onMismatch>DENYonMismatch>
    29. filter>
    30. <file>${LOG_HOME}/sys.error.logfile>
    31. <append>trueappend>
    32. <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    33. <fileNamePattern>${LOG_HOME}/%d{yyyy-MM/dd/HH}/sys.error.%i.logfileNamePattern>
    34. <maxFileSize>30MBmaxFileSize>
    35. rollingPolicy>
    36. <encoder>
    37. <Pattern>%d %p (%file:%line\)- %m%nPattern>
    38. <charset>UTF-8charset>
    39. encoder>
    40. appender>
    41. <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
    42. <resetJUL>trueresetJUL>
    43. contextListener>
    44. <root level="info">
    45. <appender-ref ref="CONSOLE"/>
    46. <appender-ref ref="ALL"/>
    47. <appender-ref ref="ERROR"/>
    48. root>
    49. <logger name="com.mgx.demo.controller" level="DEBUG"/>
    50. <logger name="com.mgx.demo.mapper" level="DEBUG"/>
    51. <logger name="springfox" level="ERROR"/>
    52. configuration>

    application

     需要打印日志的地方,在类上加上自定义注解

    3、测试

  • 相关阅读:
    VBA技术资料MF54:VBA_EXCEL实时获取鼠标位置
    有效备考浙大MEM的五个好习惯建议
    [蓝桥杯复盘] 第 3 场双周赛20231111
    QSlider 类使用教程
    Pytorch(GPU)环境安装
    【Qt】字体更大的富文本
    sylar服务器框架分析——日志系统
    Linux下安装配置各种软件和服务
    Bio-Helix丨Bio-Helix艾美捷100bp DNA ladder说明书
    关于 Redis 的这些知识 你知道哪些
  • 原文地址:https://blog.csdn.net/qq_42405688/article/details/132970648