之前写的那篇是基于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的值。
如果有好的方法,欢迎留言。