Spring Boot中Aspect实现切面(以记录日志为例)

切面Aspect是Spring的一大优势。面向切面编程往往让我们的开发更加低耦合,也大大减少了代码量,同时让我们更专注于业务模块的开发,把那些与业务无关的东西提取出去,便于后期的维护和迭代。

Maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>

日志实体类和Service

@Data
public class SysLog {
    private String className;

    private String methodName;

    private String[] methodParams;

    private Object[] paramValues;

    private Long execTime;

    private String remark;

    private String createDate;
}
@Slf4j
@Service
public class SysLogService {

    public void save(SysLog sysLog) {
        log.info(JSON.toJSONString(sysLog));
    }

}

定义日志注解

记录日志使用注解的形式,切点表达式形式无需定义

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WithSysLog {
    String value() default "";
}

声明切面,完成日志记录

这里需要对AOP有一定的了解。起码知道切点表达式、环绕通知、前置通知、后置通知等

支持注解形式和切点表达式形式

/**
 * 系统日志切面
 *
 * @Author: yezhou
 * @Date: 2019/5/9 10:40
 * @Version 1.0
 */

@Slf4j
@Aspect  //使用@Aspect注解声明一个切面
@Component
public class SysLogAspect {

    @Autowired
    private SysLogService sysLogService;

    /**
     * 使用注解的形式
     * 也可以通过切点表达式直接指定需要拦截的package, 需要拦截的class 以及 method
     * 切点表达式: execution(...)
     */
    //@Pointcut("@annotation(me.yezhou.springdemo.annotation.WithSysLog)")  //注解形式
    @Pointcut("execution(public * me.yezhou.springdemo.controller.SysLogController.*(..))")  //切点表达式形式
    public void logPointCut() {
        log.info("SysLogAspect.logPointCut");
    }

    /**
     * 环绕通知 @Around, 当然也可以使用 @Before (前置通知)  @After (后置通知)
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        log.info("SysLogAspect.around");
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        long time = System.currentTimeMillis() - beginTime;
        try {
            saveLog(point, time);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 保存日志
     *
     * @param joinPoint
     * @param time
     */
    private void saveLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SysLog sysLog = new SysLog();
        sysLog.setExecTime(time);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        sysLog.setCreateDate(dateFormat.format(new Date()));
        WithSysLog withSysLog = method.getAnnotation(WithSysLog.class);
        if (withSysLog != null) {
            //注解上的描述
            sysLog.setRemark(withSysLog.value());
        }
        //请求的 类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        String[] parameterNames = signature.getParameterNames();
        sysLog.setClassName(className);
        sysLog.setMethodName(methodName);
        sysLog.setMethodParams(parameterNames);
        //请求的参数
        Object[] args = joinPoint.getArgs();
        sysLog.setParamValues(args);

        sysLogService.save(sysLog);
    }
}

测试Controller

@RestController
public class SysLogController {

    //@WithSysLog("测试")  //注解形式
    @GetMapping("/test")  //切点表达式形式
    public String test(@RequestParam("name") String name) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            return e.getMessage();
        }
        return name;
    }

}

访问:http://127.0.0.1:8080/test?name=Joe.Ye

返回结果:

SysLogAspect.around
{"className":"me.yezhou.springdemo.controller.SysLogController","createDate":"2019-05-09 11:30:01","execTime":1000,"methodName":"test","methodParams":["name"],"paramValues":["Joe.Ye"],"remark":"测试"}

至此,我们成功实现了使用Aspect实现切面记录日志。

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/11/aspect-implementation-in-spring-boot-and-using-logging-as-an-example/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Spring Boot中Aspect实现切面(以记录日志为例)
切面Aspect是Spring的一大优势。面向切面编程往往让我们的开发更加低耦合,也大大减少了代码量,同时让我们更专注于业务模块的开发,把那些与业务无关的东西提……
<<上一篇
下一篇>>
文章目录
关闭
目 录