文章目录
- 前言
 - 1. 图示
 - 2. 源码坐标
 - 后记
 
前言
今天看了一段老业务代码,HttpServletRequest 被注入后直接用于业务逻辑。
 好奇Spring是如何解决线程安全问题。
@Controller
public class TestController {
    @Resource
    HttpServletRequest request;
    
    @ResponseBody
    @GetMapping("/test")
    public String test() {
        return request.getQueryString();
    }
}
 
本质问题是 Spring 如何装配 Controller 中 HttpServletRequest 的bean依赖
1. 图示

2. 源码坐标
可以在代码层面打断点验证,版本:SpringBoot 2.7.5 (自行集成WebStarter)
- 加载web相关的bean定义
 
ServletWebServerApplicationContext.java:141
 
- 设置工厂
 
WebApplicationContextUtils#registerWebApplicationScopes(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, javax.servlet.ServletContext)
 
- 具体的工厂方法定义(定义是从线程中取request)
 
RequestObjectFactory#getObject
 
// 关键代码块
@Override
public ServletRequest getObject() {
	return currentRequestAttributes().getRequest();
}
 
- 启动时解析依赖,将工厂方法植入
 
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
org.springframework.beans.factory.support.AutowireUtils#resolveAutowiringValue
 
- 接收请求
 
FrameworkServlet.java:1003  将响应放在ThreadLocal中
 
// 关键代码块
if (requestAttributes != null) {
	RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
 
- 回调工厂方法创建 Request
 
AutowireUtils.java:292
 
// 关键代码
return method.invoke(this.objectFactory.getObject(), args)
 
后记
- 解决 HttpServletRequest 的线程安全问题的思路 
  
- 工厂方法定义, 将 Request 的创建约束为从 ThreadLocal 中取。
 - 收到请求 ,将 Request 放入ThreadLocal 中。(请求时设置 Request)
 - Controller 实例化,使用动态代理技术回调工厂方法。(业务逻辑消费 Request)
 
 
- 建议按官方建议替换成方法参数,语义更加清晰。
 
    @ResponseBody
    @GetMapping("/test")
    public String test(HttpServletRequest request) {
        return request.getQueryString();
    }
                


















