环境:SpringBoot2.3.9.RELEASE
测试Controller类
public class MessageController {private HttpServletRequest request ;public Object resolver( Users user) {System.out.println(request) ;return user ;}}
Debug模式调试代码查看Request到底是撒

通过调试,request对象实际注入的是一个代理对象
ObjectFactoryDelegatingInvocationHandler,查看该类源码:
private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {private final ObjectFactory<?> objectFactory;public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {this.objectFactory = objectFactory;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();if (methodName.equals("equals")) {// Only consider equal when proxies are identical.return (proxy == args[0]);}else if (methodName.equals("hashCode")) {// Use hashCode of proxy.return System.identityHashCode(proxy);}else if (methodName.equals("toString")) {return this.objectFactory.toString();}try {return method.invoke(this.objectFactory.getObject(), args);}catch (InvocationTargetException ex) {throw ex.getTargetException();}}}
这是通过JDK的动态代理来实现的,该类有个属性ObjectFactory,通过名称也能也能猜出是一个对象工厂类,根据上面的调试也知道了,这里的objectFactory对象实际是RequestObjectFactory,通过这个类的.getObject()方法来获取真实的Request对象。
RequestObjectFactory源码:
("serial")private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {public ServletRequest getObject() {return currentRequestAttributes().getRequest();}public String toString() {return "Current HttpServletRequest";}}
currentRequestAttributes()方法:
private static ServletRequestAttributes currentRequestAttributes() {RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();if (!(requestAttr instanceof ServletRequestAttributes)) {throw new IllegalStateException("Current request is not a servlet request");}return (ServletRequestAttributes) requestAttr;}
currentRequestAttributes()方法:
public static RequestAttributes currentRequestAttributes() throws IllegalStateException {RequestAttributes attributes = getRequestAttributes();if (attributes == null) {if (jsfPresent) {attributes = FacesRequestAttributesFactory.getFacesRequestAttributes();}if (attributes == null) {throw new IllegalStateException("No thread-bound request found: " +"Are you referring to request attributes outside of an actual web request, " +"or processing a request outside of the originally receiving thread? " +"If you are actually operating within a web request and still receive this message, " +"your code is probably running outside of DispatcherServlet: " +"In this case, use RequestContextListener or RequestContextFilter to expose the current request.");}}return attributes;}
getRequestAttributes()方法:
public static RequestAttributes getRequestAttributes() {RequestAttributes attributes = requestAttributesHolder.get();if (attributes == null) {attributes = inheritableRequestAttributesHolder.get();}return attributes;}
源码跟踪到这里也就知道了,真实的HttpServletRequest对象是被存入在ThreadLocal对象中,线程本地变量与线程绑定了,也就是在使用Request对象时,都会从ThreadLocal中获取。
接下来看看这个HttpServletRequest对象是什么时候存入ThreadLocal中的。
Servlet处理流程:请求----》service() ----》doXXX()
SpringMVC核心控制器类DispatcherServlet的父类FrameworkServlet
FrameworkServlet类中对应的doXXX方法都有一行processRequest方法调用

processRequest方法:
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();LocaleContext localeContext = buildLocaleContext(request);RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());initContextHolders(request, localeContext, requestAttributes);try {doService(request, response);}catch (ServletException | IOException ex) {failureCause = ex;throw ex;} catch (Throwable ex) {failureCause = ex;throw new NestedServletException("Request processing failed", ex);} finally {resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) {requestAttributes.requestCompleted();}logResult(request, response, failureCause, asyncManager);publishRequestHandledEvent(request, response, startTime, failureCause);}}
下面两行代码是来创建ServletRequestAttributes对象
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
buildRequestAttributes()方法
protected ServletRequestAttributes buildRequestAttributes(HttpServletRequest request,HttpServletResponse response, RequestAttributes previousAttributes) {if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {return new ServletRequestAttributes(request, response);}else {return null; // preserve the pre-bound RequestAttributes instance}}
在这里将request和response对象都存入到了ServletRequestAttributes对象中。
接着进入initContextHolders()方法
private void initContextHolders(HttpServletRequest request,LocaleContext localeContext, RequestAttributes requestAttributes) {if (localeContext != null) {LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);}if (requestAttributes != null) {RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);}}
进入
RequestContextHolder.setRequestAttributes(requestAttributes,
this.threadContextInheritable);这行代码
public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {if (attributes == null) {resetRequestAttributes();}else {if (inheritable) {inheritableRequestAttributesHolder.set(attributes);requestAttributesHolder.remove();}else {requestAttributesHolder.set(attributes);inheritableRequestAttributesHolder.remove();}}}
该方法就是将RequestAttributes(HttpServletRequest, HttpServletResponse)对象存入到ThreadLocal中。
到此也已经说明了,在Controller中注入HttpServletRequest和HttpServletResponse是安全的。
完毕!!!
给个关注+转发,谢谢啊












