整合之前,我们要明白aop是什么,为什么要用aop,aop能帮我们做什么。
答:AOP是面向切面编程(Aspect-Oriented Programming)的简称,它是一种编程思想,旨在在面向对象编程(OOP)的基础上进行功能模块的解耦和隔离。在传统的业务处理代码中,通常需要进行事务处理、日志记录等操作,这些操作会分散到各个方法中,增加了开发和维护的难度。AOP通过预编译方式和运行期动态代理实现,在不修改源代码的情况下,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。
因此,AOP能够帮我们做以下事情:
AOP能够提高开发效率和代码质量,降低维护成本。
=========================================================================
(1)切面(Aspect):切入点和通知的集合
(2)连接点(Joinpoint):目标对象中可以被增强的所有方法
(3)通知(Advice):增强的代码(逻辑),分为前置,后置,最终,异常,环绕
(4)切入点(Pointcut):目标对象中经过匹配最终增强的方法
(5)引入(Introduction):动态的为某个类增加和减少方法
(6)目标对象(Target Object):被代理的对象
(7)AOP代理对象(AOP Proxy):AOP框架创建的代理对象,用于实现切面,调用方法
(8)织入(Weaving):将通知应用到切入点的过程
(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 环绕通知,环绕通知代表了一个完整的流程,因此环绕通知和上面的四个通知任选其一使用
(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匹配
可以使用通配符*来标识以什么开头,以什么结尾

- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-aopartifactId>
- dependency>
- <dependency>
- <groupId>com.alibabagroupId>
- <artifactId>fastjsonartifactId>
- <version>2.0.32version>
- dependency>
- package com.mgx.demo.common.enums;
-
- import lombok.AllArgsConstructor;
- import lombok.Getter;
-
-
- /**
- * @author mgx
- */
- @AllArgsConstructor
- @Getter
- public enum CharacterEnum {
-
- /**
- * 特殊字符
- */
-
- //空白
- BLANK("")
- //空格
- , SPACE(" ")
- //换行
- , NEWLINE("\n")
- //enter换行
- , ENTER("\r")
- //左斜杠
- , SLASH("/")
- //双左斜杠
- , DOUBLE_SLASH("//")
- //反斜杠
- , BACKSLASH("\\")
- //单引号
- , QUOTES("'")
- //双引号
- , DOUBLE_QUOTES("\"")
- //撇号
- , APOSTROPHE("`")
- //艾特符
- , AT("@")
- //井号
- , HASHTAG("#")
- //dollar符
- , DOLLAR("$")
- //百分号
- , PERCENT("%")
- //异或运算符 数字相同返回0,否则为1
- , XOR("^")
- //and符
- , AND("&")
- //星号
- , ASTERISK("*")
- //等于号
- , EQUAL("=")
- //下划线
- , UNDERSCORE("_")
- //点
- , DOT(".")
- //句号
- , C_DOT("。")
- //逗号
- , COMMA(",")
- //中文逗号
- , C_COMMA(",")
- //管道符
- , PIPE("|")
- //双管道符
- , DOUBLE_PIPE("||")
- //问号
- , Q_MARK("?")
- //叹号
- , E_MARK("!")
- //加号
- , PLUS("+")
- //连字号、短横杠、减号
- , HYPHEN("-")
- //小于符
- , LT("<")
- //大于符
- , GT(">")
- //冒号
- , COLON(":")
- //分号
- , SEMICOLON(";")
- //中文分号
- , C_SEMICOLON(";")
- //左圆括号 round
- , L_R_BRACKETS("(")
- //右圆括号
- , R_R_BRACKETS(")")
- //左右圆括号
- , R_BRACKETS("()")
- //左方括号 square
- , L_S_BRACKETS("[")
- //右方括号
- , R_S_BRACKETS("]")
- //左右方括号
- , S_BRACKETS("[]")
- //左大括号 curly
- , L_C_BRACKETS("{")
- //右大括号
- , R_C_BRACKETS("{")
- //左右大括号
- , C_BRACKETS("{}")
- ;
-
- private final String character;
-
- public String value() {
- return character;
- }
-
- }
- package com.mgx.demo.utils;
-
- import com.alibaba.fastjson.JSON;
- import com.mgx.demo.common.enums.CharacterEnum;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.web.context.request.RequestAttributes;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
-
- import javax.servlet.http.HttpServletRequest;
- import java.util.Arrays;
- import java.util.Objects;
-
- /**
- * @author mgx
- */
- @Slf4j
- public class LogUtil {
-
- /**
- * 接口请求日志
- *
- * @param param 接口获取参数
- */
- public static void param(Object... param) {
- RequestAttributes ra = RequestContextHolder.getRequestAttributes();
- ServletRequestAttributes sra = (ServletRequestAttributes) ra;
- if (Objects.nonNull(sra)) {
- HttpServletRequest request = sra.getRequest();
- String url = request.getRequestURL().toString();
- log.info("===============++++请求++++================\n地址:{}\n参数:{}", url, Objects.isNull(param) ? CharacterEnum.BLANK.value() : Arrays.toString(param));
- }
- }
-
- /**
- * 接口请求日志
- *
- * @param param 封装后的参数,若数据结构较复杂,请考虑json转化string耗时及性能
- */
- public static void paramObject(Object param) {
- RequestAttributes ra = RequestContextHolder.getRequestAttributes();
- ServletRequestAttributes sra = (ServletRequestAttributes) ra;
- if (Objects.nonNull(sra)) {
- HttpServletRequest request = sra.getRequest();
- String url = request.getRequestURL().toString();
- log.info("===============++++请求++++================\n地址:{}\n参数:{}", url, Objects.isNull(param) ? CharacterEnum.BLANK.value() : JSON.toJSONString(param));
- }
- }
-
- public static void logRequest(HttpServletRequest request) {
- log.info("===============++++请求++++================\n地址:{}\n方法:{}\nIP:{}", request.getRequestURL().toString(), request.getMethod(), request.getRemoteAddr());
- }
-
- }
- package com.mgx.demo.config.aop;
-
- import com.alibaba.fastjson.JSON;
-
- import com.mgx.demo.annotation.LogRequestParam;
- import com.mgx.demo.utils.LogUtil;
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.stereotype.Component;
-
- /**
- * 自动打印日志
- */
- @Aspect
- @Component
- public class WebLogAspect {
- private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
-
- @Pointcut("execution(public * com.mgx.demo.controller.*.*(..))")
- public void webLog() {}
-
- @AfterReturning(returning = "ret", pointcut = "webLog()")
- public void doAfterReturning(Object ret) {
- // 处理完请求,返回内容
- logger.info("RESPONSE : {}", JSON.toJSONString(ret));
- }
-
- @Before("@annotation(logRequestParam) || @within(logRequestParam)")
- public void doRequestParamLog(JoinPoint joinPoint, LogRequestParam logRequestParam) {
- // 获取方法参数
- Object[] args = joinPoint.getArgs();
- if (args != null) {
- if (args.length == 1) {
- LogUtil.paramObject(args[0]);
- } else {
- LogUtil.param(args);
- }
- }
- }
-
- }
- package com.mgx.demo.annotation;
-
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- /**
- * @author mgx
- */
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface LogRequestParam {
- }
- "1.0" encoding="UTF-8"?>
- <configuration>
-
- <springProperty scope="context" name="logPath" source="project.log.config" defaultValue="${user.home}/springboot-mgx/logs"/>
- <property name="LOG_HOME" value="${logPath}"/>
-
-
-
- <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
-
- <pattern>%date{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) (%file:%line\)- %m%npattern>
-
- <charset>UTF-8charset>
- encoder>
- appender>
-
-
-
-
- <appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <File>${LOG_HOME}/sys.logFile>
-
-
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-
-
- <fileNamePattern>${LOG_HOME}/%d{yyyy-MM/dd/HH}/sys.%i.logfileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
-
- <maxFileSize>30MBmaxFileSize>
- timeBasedFileNamingAndTriggeringPolicy>
- rollingPolicy>
- <encoder>
-
- <pattern>%d %p (%file:%line\)- %m%npattern>
-
- <charset>UTF-8charset>
- encoder>
- appender>
-
-
- <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>ERRORlevel>
- <onMatch>ACCEPTonMatch>
- <onMismatch>DENYonMismatch>
- filter>
- <file>${LOG_HOME}/sys.error.logfile>
- <append>trueappend>
- <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
- <fileNamePattern>${LOG_HOME}/%d{yyyy-MM/dd/HH}/sys.error.%i.logfileNamePattern>
- <maxFileSize>30MBmaxFileSize>
- rollingPolicy>
- <encoder>
- <Pattern>%d %p (%file:%line\)- %m%nPattern>
- <charset>UTF-8charset>
- encoder>
- appender>
-
- <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
- <resetJUL>trueresetJUL>
- contextListener>
-
-
- <root level="info">
- <appender-ref ref="CONSOLE"/>
- <appender-ref ref="ALL"/>
- <appender-ref ref="ERROR"/>
- root>
-
-
-
-
- <logger name="com.mgx.demo.controller" level="DEBUG"/>
- <logger name="com.mgx.demo.mapper" level="DEBUG"/>
- <logger name="springfox" level="ERROR"/>
-
- configuration>
application

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


