aop 日志

                版权声明:本文为博主原创文章,未经博主允许不得转载。                    https://blog.csdn.net/j1231230/article/details/81837022                </div>
                      <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-cd6c485e8b.css">
                          <div id="content_views" class="markdown_views">
        <!-- flowchart 箭头图标 勿删 -->
        <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
          <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
        </svg>
        <p>AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。一般来说,我们项目中的日志几乎会遍布所有controller,不利于统一管理,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。</p>

使用”横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

接下来,我们看一下如何使用AOP给springboot项目添加日志:

一.引入AOP的依赖包

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
 
 
  • 1
  • 2
  • 3
  • 4

二.添加AOP的全局类

@Aspect
@Component
public class WebLogAspect {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private LogService logService;

    @Autowired
    private UserService userService;

    private String url;

    private String ip;

    private Integer port;

    private User user;

    @Pointcut("execution(public * com.ytint.bb6.controller..*.*(..))")
    public void webLog() {
    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录请求内容,这里只记录非GET请求的日志信息
        if (!request.getMethod().equals("GET")) {
            logger.info("请求URL: " + request.getRequestURL().toString());
            url = request.getRequestURI();
            ip = request.getRemoteHost();
            port = request.getRemotePort();
            user = userService.getCurrentUser();
        }
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        Integer logType = LogType.OPERATION.getId();
        if (ret instanceof ResultInfo) {
            ResultInfo result = (ResultInfo) ret;
            String msg = result.getMsg();
            String module = result.getModule();
            Integer code = result.getCode();
            if (UtilValidate.isNotEmpty(msg)) {
                logger.info(msg);
                // 操作模块返回200才存储到日志表
                if (code.equals(200)) {
                    logService.save(user, ip, port, msg, logType, module, url);
                }
            }
        }

    }

    @AfterThrowing(pointcut = "webLog()", throwing = "e")
    public void doException(JoinPoint jp, Throwable e) {
        if (e != null) {
            Logger logger = LoggerFactory.getLogger(jp.getSignature().getClass());
            logger.error("程序发生了异常:" + e.getMessage(), e);
        }
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

Spring使用AspectJ注解来声明通知方法

@After:会在目标方法返回或抛出异常后调用

@AfterReturning:会在目标方法返回后调用

@AfterThrowing:会在目标方法抛出异常后调用

@Around:会将目标方法封装起来

@Before:会在目标方法调用之前执行

使用@Pointcut定义切面

@Pointcut后面括号里的内容是切面表达式:

@Pointcut("execution(public * com.yt.controller..*.*(..))")
 
 
  • 1

表达式含义如下:

1) execution(): 表达式主体;

2) public *:表示返回类型, *号表示所有的类型;

3) 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.yt.controller包、子孙包下所有类的方法;

4) 第二个*号:表示类名,*号表示所有的类;

5) *(..):表示方法名,*号表示所有的方法,括号里面表示方法的参数,..表示任何参数;

webLog()方法定义了一个可重用的切点,这样我们就不必把同样的切点表达式傻傻的写好多遍了,只要在每次需要的时候引用它就可以了,webLog方法的实际内容并不重要,他本身只是一个标识,供@Pointcut注解依附。

在日志中添加模块信息

如果我们不只想获取当前方法的URL,参数等基本信息,还想获取它来源于某一个controller模块该怎么办呢,我这里采用了一个有点傻的方法,可以在返回的结果对象中添加一个模块字段module,把对应的controller信息放在模块里,这样输出日志时就可以知道当前请求是来源于哪个controller了。如果大家有更好的方式,欢迎交流~

本篇博客部分参考了以下两篇博客,送上花花~~~

https://www.cnblogs.com/hongwz/p/5764917.html
https://www.cnblogs.com/30go/p/8443522.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值