import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Map; @Controller @RequestMapping(value = "/tool") public class ToolController { private Logger logger = LoggerFactory.getLogger(ToolController.class); @ResponseBody @RequestMapping(value = "/jie8583", method = RequestMethod.GET,produces = "application/json;charset=UTF-8") public String jie8583(String msg){ MDC.put("sysUUID","fds"); logger.info("jie8583"); return ""; } @ResponseBody @RequestMapping(value = "/jie8581", method = RequestMethod.GET,produces = "application/json;charset=UTF-8") public String jie8581(String msg){ logger.info("jie"); return ""; } }
代码如上,今天使用spring mvc + logback ,在用MDC (MDC自行百度)做日志区分时,发现
请求A 设置的MDC 参数值 偶尔会带到 B请求中。 百度查询可知MDC 是通过ThreadLocal 已当前
线程为key , 存放设置的值。
请求A 在执行完成后难道不是自动销毁线程吗? 怎么会带到了B请求呢?
对上述代码修改验证 线程是否自动销毁:
private Logger logger = LoggerFactory.getLogger(ToolController.class); public static final ThreadLocal<String> tl = new ThreadLocal<>(); @ResponseBody @RequestMapping(value = "/jie8583", method = RequestMethod.GET,produces = "application/json;charset=UTF-8") public String jie8583(String msg){ tl.set("83的线程"); return ""; } @ResponseBody @RequestMapping(value = "/jie8581", method = RequestMethod.GET,produces = "application/json;charset=UTF-8") public String jie8581(String msg){ System.out.println(tl.get()); return ""; }
先请求一次 /jie8583 。 然后多次请求 /jie8581 , 日志如下:
null null null null null 83鐨勭嚎绋? null null null null
(乱码忽略), 说明有一次请求竟然获取到我 jie8583请求设置的值。 所以请求完成后线程并没有销毁,而是被复用了,
至于为什么没有销毁,百度说是spring 为了提高单例模式性能而借助threadlocal 实现多线程,还没搞明白。
建议在使用完成threadLocal后 ,调用tl.remove 清空。