天天看點

RequestMappingHandlerMapping注入的正确姿勢

文章目錄

    • 簡述
    • 基本知識點
    • 第一種方式:Controller注入
    • 第二種方式:從IOC的ApplicationContext裡面擷取

簡述

RequestMappingHandlerMapping是springMVC裡面的核心Bean,spring把我們的controller解析成RequestMappingInfo對象,然後再注冊進RequestMappingHandlerMapping中,這樣請求進來以後就可以根據請求位址調用到Controller類裡面了。

Controller畢竟是寫死的,在有的情況下我們可能還需要動态地注冊一些API到springMVC的容器中,就需要注入了。但是注入的時候,會發現不一定好使,本文專門做一下解釋說明。

基本知識點

  1. RequestMappingHandlerMapping對象本身是spring來管理的,可以通過ApplicationContext取到,是以并不需要我們建立。
  2. 在SpringMVC架構下,會有兩個ApplicationContext,一個是Spring IOC的上下文,這個是java web架構的Listener裡面配置,就是我們經常用的web.xml裡面的org.springframework.web.context.ContextLoaderListener,由它來完成IOC容器的初始化和bean對象的注入。
  3. 另外一個是ApplicationContext是由org.springframework.web.servlet.DispatcherServlet完成的,具體是在org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext()這個方法做的。而這個過程裡面會完成RequestMappingHandlerMapping這個對象的初始化。

第一種方式:Controller注入

你直接在Controller按照下述方法寫:

@Autowired
    RequestMappingHandlerMapping requestMappingHandlerMapping;
           

這樣就可以了,很簡單,非Controller,Autowired是不行的。

第二種方式:從IOC的ApplicationContext裡面擷取

這個方式是自己當時發現的,從IOC的applicationContext裡面擷取。

如果你不想在Controller裡面引用的話,就可以考慮這種方式,可以在任何地方使用。

如下所示:

private RequestMappingHandlerMapping requestMappingHandlerMapping;
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }
    private RequestMappingHandlerMapping getRequestMappingHandlerMapping(){
        if (this.requestMappingHandlerMapping==null){
            XmlWebApplicationContext xmlApplicationContext=(XmlWebApplicationContext) applicationContext;
            ApplicationContext servletApplicationContext=(ApplicationContext)(xmlApplicationContext.getServletContext().getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX+xmlApplicationContext.getServletConfig().getServletName()));
            this.requestMappingHandlerMapping=servletApplicationContext.getBean(RequestMappingHandlerMapping.class);
        }
        return this.requestMappingHandlerMapping;
    }
           

裡面用到了ApplicationContextAware,這個比較簡單。

上面的那個代碼看着可能有點長,但是比較簡單。

整體來講就是:

springMVC有一個ApplicationContext,但是他初始化完了以後,就把這個對象塞到了ServletContext的屬性裡面去了,屬性名是:FrameworkServlet.SERVLET_CONTEXT_PREFIX+xmlApplicationContext.getServletConfig().getServletName()。而這個ServletContext可以從SpringIOC的容器裡面取出來,是以就可以通過SpringIOC的Context取到SpringMVC的Context,是以就可以取到RequestMappingHandlerMapping。

在不知道這個事情的時候,看了網上的一些文章,就直接用注解自動注入,但是一直報錯沒有這個bean,最後花了我不少心思找到了這個,親測可用。

這邊稍微有一個問題注意下,就是使用這個方法的時機,一定要在servlet加載完了以後再使用,否則這個對象也是沒有的。servlet加載的時候才會初始化這個Context。

如果你希望在啟動過程中去動态注冊API的話,那麼我推薦你使用Controller裡面的注解注入,同時使用PostContruct注解;或者重寫一下DispatcherServlet這個類的init方法,完成父類的init方法以後,再去執行你的業務邏輯,也肯定沒有問題,我是這樣幹的。