最近在使用工厂模式来进行开发,发现比单例模式好用多了,但问题也随之出现了,在开发过程中有一些业务上的疑惑,想知道在工厂模式下的@Service服务层有没有可以直接获取当次请求的HttpServletRequest对象,我想在服务层直接能使用这个对象,而不是要在控制层把它当成参数传过来,就算可以当成参数传进去服务层里面,HttpServlet对象有些方法莫名其妙的还不支持在服务层中使用,我记得大概的爆红是说不能在非Context下使用。
在 Spring Boot 中,可以通过使用 org.springframework.web.context.request.RequestContextHolder 类来获取当前请求的 HttpServletRequest 对象。
具体实现方式如下:
在服务层中注入 org.springframework.web.context.request.RequestContextHolder,然后在需要使用 HttpServletRequest 的方法中调用RequestContextHolder.currentRequestAttributes() 方法获取 RequestAttributes 对象,再调用 getRequest() 方法获取 HttpServletRequest 对象。
例如:
@Service
public class MyService {
@Autowired
private RequestContextHolder requestContextHolder;
public void someMethod() {
HttpServletRequest request = ((ServletRequestAttributes) requestContextHolder.currentRequestAttributes()).getRequest();
//...
}
}
需要注意的是这种方式需要使用 org.springframework.web.filter.RequestContextFilter 进行配置,保证在请求进入之前就能获取到 request。
另外,如果你需要在非web线程中使用request,可以考虑使用ThreadLocal或者将request当成参数传递。
springmvc的入口dispatchservlet,在处理请求的时候,就把request存到threadLocal里面了,你要用直接取就行了,
RequestContextHolder.getRequestAttributes(),自己去强转就能拿到request了
SpringWebMvc提供了一个RequestContextHolder就是持有上下文的Request容器类,有个方法返回RequestAttributes需要强转成HttpServletRequest对象,具体使用如:
HttpServletRequest reques = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
实现原理:
首先就是RequestContextHolder通过ThreadLocal保存当前线程下的request,
//存储request
private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
//存储可被子线程继承的request
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");
然后他是怎么设值得呢?
查源码从DispatcherServlet 出发,来到FrameworkServlet发现这个类类重写了service(),doGet(),doPost()等方法,这些实现里面都有一个预处理方法processRequest(request, response);这个方法里面就有把上下文的Request设置到RequestContextHolder
spring有个东西叫 RequestContextHolder;
里面有个东西叫 ThreadLocal requestAttributesHolder