环境:SpringBoot2.3.9.RELEASE
- 测试Controller类
@RestController
@RequestMapping("/message")
public class MessageController {
@Resource
private HttpServletRequest request ;
@PostMapping("/resolver")
public Object resolver(@RequestBody 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;
}
@Override
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源码:
@SuppressWarnings("serial")
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
@Override
public ServletRequest getObject() {
return currentRequestAttributes().getRequest();
}
@Override
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,
@Nullable HttpServletResponse response, @Nullable 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,
@Nullable LocaleContext localeContext, @Nullable 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是安全的。
完毕!!!