spring aop实现log 日志跟踪

之前写的那篇是基于springboot的(https://www.cnblogs.com/yaoyuan2/p/10302802.html),由于遗留项目用的是spring,因此需要在spring基础上实现。

代码结构

web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
           classpath:spring-application.xml
       </param-value>
</context-param>
... <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- <init-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </init-param> --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

spring-application.xml

<context:component-scan base-package="com.ebc.config" />

因为下边com.ebc.config.LogAspectConfig用到了

@Aspect
@Component

所以,为了扫描到才加以上

spring-servlet.xml

<beans 
  ...
    xmlns:aop="http://www.springframework.org/schema/aop"
    
     http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
     ">
<!-- 启动对@AspectJ注解的支持 -->  
<aop:aspectj-autoproxy/>

com.ebc.config.LogAspectConfig

package com.ebc.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import cn.hutool.core.util.IdUtil;

@Aspect
@Component
public class LogAspectConfig {
    /**
     * 第1个* 方法属性 public/private/....
     * 接着,连着的2个*,包
     * 然后的1个*,类
     * 最后1个*,方法
     * (..)方法里的参数。..标示任意参数
     */
    @Pointcut("execution(* com.ebc.**.*.*(..))")
    public void methodCut(){}
    /**
     * 方法调用之前调用
     */
    @Before("methodCut()")
    public void doBefore(JoinPoint joinPoint) throws InterruptedException{
        String requestId = String.valueOf(IdUtil.objectId());
        MDC.put("requestId",requestId);
    }

    /**
     * 方法之后调用
     */
    @After("methodCut()")
    public void doAfter(JoinPoint joinPoint) {
        MDC.clear();
    }

}

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <CONSOLE name="CONSOLE">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] %-5level | %C.%M:%L - %m%n"/>
    </CONSOLE>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="CONSOLE"/>
    </Root>
    <logger name="com.ebc.web" level="INFO" />
     <logger name="com.ebc.disruptor" level="INFO" />
  </Loggers>
</Configuration>

测试输出:

2019-01-25 10:29:10.609 [5c4a7476cbb0db4b262e20cf] INFO  | com.ebc.web.IndexController.index:25 - 接收参数:name=遥远2,minernum=222
一月 25, 2019 10:29:10 上午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@105fac24: startup date [Fri Jan 25 10:29:10 GMT+08:00 2019]; root of context hierarchy
2019-01-25 10:29:10.625 [5c4a7476cbb0db4b262e20cf] INFO  | com.ebc.disruptor.UserMinerProducer.publish:16 - 接收:5c4a7476cbb0db4b262e20cf,222
2019-01-25 10:29:10.635 [] INFO  | com.ebc.disruptor.UserMinerHandler.onEvent:18 - userName=5c4a7476cbb0db4b262e20cf,amount=222

mdc的本质采用ThreadLocal,一个线程(含子线程)内共享变量。

而现在的项目用的是disruptor,跨主线程,因此在UserMinerHandler(消费端)无法获取到共享变量。采用了一个变通的方法,就是业务代码传递过去。所以,userName里才填充了MDC的值。

如果有好的方法,欢迎留言。

原文地址:https://www.cnblogs.com/yaoyuan2/p/10318344.html