• Springboot中Aspect实现切面(以记录日志为例)


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

    好了,废话少说!我们直接步入正题

    以系统日志为例
    首先,我们先做一些准备工作。

    1、新建一个Springboot工程
    2、添加必要的依赖
    AOP 必须

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    gson主要是我用于数据的处理,不是必须的

    <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.1</version>
    </dependency>
    个人喜好
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </dependency>
    3、日志实体类和service
    package com.space.aspect.bo;

    import lombok.Data;

    /**
    * 系统日志bo
    * @author zhuzhe
    * @date 2018/6/4 9:36
    * @email 1529949535@qq.com
    */
    @Data
    public class SysLogBO {

    private String className;

    private String methodName;

    private String params;

    private Long exeuTime;

    private String remark;

    private String createDate;
    }
    package com.space.aspect.service;

    import com.space.aspect.bo.SysLogBO;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;

    /**
    * @author zhuzhe
    * @date 2018/6/4 9:41
    * @email 1529949535@qq.com
    */
    @Slf4j
    @Service
    public class SysLogService {

    public boolean save(SysLogBO sysLogBO){
    // 这里就不做具体实现了
    log.info(sysLogBO.getParams());
    return true;
    }
    }
    4、定义日志注解
    这里呢,我们记录日志使用注解的形式。所以,先定义一个注解

    package com.space.aspect.anno;

    import java.lang.annotation.*;

    /**
    * 定义系统日志注解
    * @author zhuzhe
    * @date 2018/6/4 9:24
    * @email 1529949535@qq.com
    */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SysLog {
    String value() default "";
    }
    5、声明切面,完成日志记录
    以上4点我们的准备工作已经完成。接下来就是重点了

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

    package com.space.aspect.aspect;

    import com.google.gson.Gson;
    import com.space.aspect.anno.SysLog;
    import com.space.aspect.bo.SysLogBO;
    import com.space.aspect.service.SysLogService;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;

    import java.lang.reflect.Method;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;

    /**
    * 系统日志切面
    * @author zhuzhe
    * @date 2018/6/4 9:27
    * @email 1529949535@qq.com
    */
    @Aspect // 使用@Aspect注解声明一个切面
    @Component
    public class SysLogAspect {

    @Autowired
    private SysLogService sysLogService;

    /**
    * 这里我们使用注解的形式
    * 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
    * 切点表达式: execution(...)
    */
    @Pointcut("@annotation(com.space.aspect.anno.SysLog)")
    public void logPointCut() {}

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

    /**
    * 保存日志
    * @param joinPoint
    * @param time
    */
    private void saveLog(ProceedingJoinPoint joinPoint, long time) {
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    SysLogBO sysLogBO = new SysLogBO();
    sysLogBO.setExeuTime(time);
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    sysLogBO.setCreateDate(dateFormat.format(new Date()));
    SysLog sysLog = method.getAnnotation(SysLog.class);
    if(sysLog != null){
    //注解上的描述
    sysLogBO.setRemark(sysLog.value());
    }
    //请求的 类名、方法名
    String className = joinPoint.getTarget().getClass().getName();
    String methodName = signature.getName();
    sysLogBO.setClassName(className);
    sysLogBO.setMethodName(methodName);
    //请求的参数
    Object[] args = joinPoint.getArgs();
    try{
    List<String> list = new ArrayList<String>();
    for (Object o : args) {
    list.add(new Gson().toJson(o));
    }
    sysLogBO.setParams(list.toString());
    }catch (Exception e){ }
    sysLogService.save(sysLogBO);
    }
    }
    6、测试
    接下来,我们就来测试一下吧

    package com.space.aspect.controller;

    import com.space.aspect.anno.SysLog;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;

    /**
    * @author zhuzhe
    * @date 2018/6/4 9:47
    * @email 1529949535@qq.com
    */
    @RestController
    public class TestController {

    @SysLog("测试")
    @GetMapping("/test")
    public String test(@RequestParam("name") String name){
    return name;
    }
    }
    启动项目,访问我们的test方法。

    我们在service里打一个断点

    可以看到,我们所需要的值都成功拿到了。

    这样,我们就成功实现了使用Aspect实现切面记录日志。

    源码:https://github.com/zhuzhegithub/springboot-aop-aspect

    转载请务必保留此出处(原作者):https://blog.csdn.net/zhuzhezhuzhe1

    版权声明:本文为原创文章,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。

    https://blog.csdn.net/zhuzhezhuzhe1


    ————————————————
    版权声明:本文为CSDN博主「朱_哲」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zhuzhezhuzhe1/article/details/80565067

  • 相关阅读:
    PHP算法练习2:(175. 组合两个表)
    swoole(4)网络服务模型(多进程master-worker模型)
    swoole(3)网络服务模型(单进程阻塞、预派生子进程、单进程阻塞复用模型)
    swoole(2)swoole进程结构
    Shell glob
    NSInteger和BOOL的底层类型
    Mac OS X和iOS上基本数据类型的字节数
    LP64是什么意思
    Lenovo Y430P安装Linux无线网卡
    JavaScript中的原型继承原理
  • 原文地址:https://www.cnblogs.com/javalinux/p/14898532.html
Copyright © 2020-2023  润新知