关于获取到HttpServletRequest对象的研究

在springmvc项目中,要在一次请求处理过程中拿到HttpServletRequest对象,一般是在controller方法中,直接引入HttpServletRequest参数。这样,springmvc在调用这个方法的时候,会根据方法的参数类型,传入对应的参数。

但还有一种方法,不需要引入参数,而是通过RequestContextHolder类的getRequestAttributes()方法获取到的RequestAttributes对象直接获取到HttpServletRequest对象,一般是采用这样的代码:

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

那么为什么,这样的代码就可以直接获取到HttpServletRequest对象呢?

首先RequestAttributes接口在这里实现的对象是ServletRequestAttributes,也就是说RequestContextHolder.getRequestAttributes()返回的是ServletRequestAttributes对象。所以必然要实例化这个ServletRequestAttributes类。

其构造函数:

public ServletRequestAttributes(HttpServletRequest request, @Nullable HttpServletResponse response) {
	this(request);
	this.response = response;
}

从这个构造函数就可以看出来,实际上我们获取到的HttpServletRequest对象,就是在这个类实例化的时候传进来保存在这个类中的。看这里的代码,我们可以知道,HttpServletResponse对象也可以用这样的方法获取到。

那么这个ServletRequestAttributes是在哪里实例化的呢?

只需要在这个构造函数中下断点,然后启动springmvc项目,然后从浏览器发起请求,然后往上找堆栈信息,就可以定位到OrderedRequestContextFilter类的doFilterInternal方法。这个方法是从RequestContextFilter继承的。

OrderedRequestContextFilter类是springmvc内置的过滤器,所以每个请求都会经过这个过滤器的处理。

创建好的ServletRequestAttributes对象被传递进initContextHolders方法。

然后看initContextHolders方法中的如下语句:

RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);

setRequestAttributes方法中执行了如下语句:

requestAttributesHolder.set(attributes);

requestAttributesHolder是ThreadLocal对象:

private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
			new NamedThreadLocal<>("Request attributes");

也就是说,RequestAttributes对象保存在了线程本地变量表中。

然后再回头看到一下RequestContextHolder.getRequestAttributes():

RequestAttributes attributes = requestAttributesHolder.get();

这里就是直接从requestAttributesHolder中获取,实际上就是获取属于本线程的RequestAttributes对象。

总结一下:之所以能获取到HttpServletRequest对象,说到底,还是曾经把这个对象保存起来了。做这个事情的是OrderedRequestContextFilter这个过滤器。

在sprintboot中,这个功能,是通过WebMvcAutoConfiguration中注册OrderedRequestContextFilter,而实际上,只需要注册RequestContextFilter就可以了。在springmvc项目中,如果使用web.xml配置项目,那么可能需要在web.xml中手动配置RequestContextFilter。

该过滤器继承自OncePerRequestFilter,也就是说,它在整个请求处理过程中最多只会被应用一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值