为什么在SpringMVC和SpringBoot中可以直接注入HttpServletRequest

发布于 2022-09-12 23:55:24 字数 774 浏览 32 评论 0

如题:为什么在SpringMVC和SpringBoot中可以直接注入HttpServletRequest对象。

代码示例

@Autowired
private HttpServletRequest request;

@GetMapping(value = "/rest/current")
public ReturnResult current() {
    System.out.println(request.getRequestURL().toString());
    JSONObject res = new JSONObject();
    res.put("requestId", UUID.randomUUID().toString());
    res.put("datatime", DateUtils.getDatetime());
    return ReturnResult.get(res);
}

理论上,我们需要注入其他包中的对象的时候,是必须在@Configuration修饰的类下面使用@Bean进行方法修饰的才行的,如下所示:

@Configuration
public class ApplicationConfig {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

那为什么HttpServletRequest这个对象如此优秀,可以直接注入呢?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

以可爱出名 2022-09-19 23:55:24

它这么秀的根本原因是因为……注入的并不是真正的 HttpServletRequest,只是一个代理对象,其背后的核心对象是 org.springframework.web.context.support.WebApplicationContextUtils.RequestObjectFactory

你看这个类长啥样:

private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {

        @Override
        public ServletRequest getObject() {
        
                // 获取当前 ServletRequest
            return currentRequestAttributes().getRequest();
        }

        @Override
        public String toString() {
            return "Current HttpServletRequest";
        }
    }
    
    
    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;
    }

那这个“当前 ServletRequest”从哪来呢?

Servlet 除了 ServletContextListener 之外,还有一个 ServletRequestListener

public interface ServletRequestListener extends EventListener {
    void requestDestroyed(ServletRequestEvent var1);

    void requestInitialized(ServletRequestEvent var1);
}

只要你注册了这个,就能在请求前执行requestDestroyed

Spring 弄了一个 org.springframework.web.context.request.RequestContextListener,在这个里面获取并存储的

@Override
    public void requestInitialized(ServletRequestEvent requestEvent) {
        if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
            throw new IllegalArgumentException(
                    "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
        }
        HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
        ServletRequestAttributes attributes = new ServletRequestAttributes(request);
        request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
        LocaleContextHolder.setLocale(request.getLocale());
        
        // 存储 ServletRequest
        RequestContextHolder.setRequestAttributes(attributes);
    }
草莓酥 2022-09-19 23:55:24

特殊情况特殊处理。不要把ioc死板的搬过来。

Request, Response, HttpEntity等都是特殊处理的。而且这几个对象和请求有关,不在窗口里面。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文