2017-01-09 71 views
0

我在與兩個上下文彈簧MVC應用程序(如我AbstractAnnotationConfigDispatcherServletInitializer子類中聲明)春天:`@ autowired`在哪裏尋找豆子?

  • 根上下文包含模型,倉庫等
  • MVC的上下文包含控制器

現在,我可以將資源庫注入控制器,但爲什麼?

  • Web上下文是否也包含根上下文中的bean(類似於@Import ??)。該文檔暗示他們有父母 - 子女關係,但通過檢查Web上下文,我不在其中。
  • 或者,@Autowired是否可以跨多個上下文工作?而且,如果是這樣,怎麼樣?
+0

你可以發佈你的web.xml文件嗎? – mlg

+0

我沒有web.xml,初始化是通過 –

回答

1

這兩個上下文都存儲在同一個servlet上下文中。

如果你注意到,AbstractDispatcherServletInitializer,父類的AbstractAnnotationConfigDispatcherServletInitializer,不登記的onStartup方法

@Override 
    public void onStartup(ServletContext servletContext) throws ServletException { 
     super.onStartup(servletContext); 
     registerDispatcherServlet(servletContext); 
    } 

要做到這一點,首先調用其父onStartup方法,其中它首先將其由創建rootApplicationContext在AbstractAnnotationConfigDispatcherServletInitializer類的createRootApplicationContext方法,並最終將其添加到在onStartup方法獲得ServletContext的:

@Override 
    public void onStartup(ServletContext servletContext) throws ServletException { 
     registerContextLoaderListener(servletContext); 
    } 

    /** 
    * Register a {@link ContextLoaderListener} against the given servlet context. The 
    * {@code ContextLoaderListener} is initialized with the application context returned 
    * from the {@link #createRootApplicationContext()} template method. 
    * @param servletContext the servlet context to register the listener against 
    */ 
    protected void registerContextLoaderListener(ServletContext servletContext) { 
     WebApplicationContext rootAppContext = createRootApplicationContext(); 
     if (rootAppContext != null) { 
      ContextLoaderListener listener = new ContextLoaderListener(rootAppContext); 
      listener.setContextInitializers(getRootApplicationContextInitializers()); 
      servletContext.addListener(listener); 
     } 
     else { 
      logger.debug("No ContextLoaderListener registered, as " + 
        "createRootApplicationContext() did not return an application context"); 
     } 
    } 

而且在這之後,AbstractDispatcherServletInitializer調用其registerDispatcherServlet方法,其中調用抽象方法createServletApplicationContext是在AbstractAnnotationConfigDispatcherServletInitializer類,並創建了dispatcherServlet,然後將其添加到同一個ServletContext的:

/** 
    * Register a {@link DispatcherServlet} against the given servlet context. 
    * <p>This method will create a {@code DispatcherServlet} with the name returned by 
    * {@link #getServletName()}, initializing it with the application context returned 
    * from {@link #createServletApplicationContext()}, and mapping it to the patterns 
    * returned from {@link #getServletMappings()}. 
    * <p>Further customization can be achieved by overriding {@link 
    * #customizeRegistration(ServletRegistration.Dynamic)} or 
    * {@link #createDispatcherServlet(WebApplicationContext)}. 
    * @param servletContext the context to register the servlet against 
    */ 
    protected void registerDispatcherServlet(ServletContext servletContext) { 
     String servletName = getServletName(); 
     Assert.hasLength(servletName, "getServletName() must not return empty or null"); 

     WebApplicationContext servletAppContext = createServletApplicationContext(); 
     Assert.notNull(servletAppContext, 
       "createServletApplicationContext() did not return an application " + 
       "context for servlet [" + servletName + "]"); 

     FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext); 
     dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers()); 

     ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); 
     Assert.notNull(registration, 
       "Failed to register servlet with name '" + servletName + "'." + 
       "Check if there is another servlet registered under the same name."); 

     registration.setLoadOnStartup(1); 
     registration.addMapping(getServletMappings()); 
     registration.setAsyncSupported(isAsyncSupported()); 

     Filter[] filters = getServletFilters(); 
     if (!ObjectUtils.isEmpty(filters)) { 
      for (Filter filter : filters) { 
       registerServletFilter(servletContext, filter); 
      } 
     } 

     customizeRegistration(registration); 
    } 

這就是爲什麼你可以注入的存儲庫控制器,因爲2個上下文位於同一個ServletContext中。

0

我通常從AbstractAnnotationConfigDispatcherServletInitializer.getRootConfigClasses()返回一個單獨的背景下,這個班則有ComponentScan和/或進口這些發現@Configurations和@Components等

除非你明確地創建親子環境中,所有的豆類,組件,服務最終在一個ApplicationContext中。通過顯式的我的意思是你必須在調用refresh()之前調用ApplicationContext上的setParent(),所以你通常知道你什麼時候完成了它。

這意味着可以@AutoWire到從同一個應用程序的上下文的其它彈簧豆(在自動裝配Autowired豆可以是從父上下文,如果你有嵌套上下文)

編輯 如果使用AbstractAnnotationConfigDispatcherServletInitializer.getServletConfigClasses()和從你的初始化程序返回兩個上下文,servletConfig上下文將是一個子進程,並且根上下文將是父進程。這意味着您可以將Bean從RootConfig上下文自動裝入到servletConfig上下文bean中,但不能以其他方式進行。 - 這就是爲什麼我通常只會從getRootConfigClasses()nullgetServletConfigClasses()返回上下文。

+0

提到的子類來實現的,通常,同一個類也定義了一個調度器servlet上下文,並且文檔明確指出spring mvc中通常有兩個上下文。 '.setParent'可能在這兩個bean的內部被調用 –

+0

個人我只使用父子上下文,如果生命週期不同,並且父母可以在沒有孩子的情況下生活 - 這不是在web應用中的情況,所以我只從getRootConfigClasses()返回一個類。 –