1. 程式人生 > >springMvc和spring的父子容器

springMvc和spring的父子容器

何為父子容器?

Spring正題框架的核心概念中, 容器是核心思想。用來管理bean 的整個生命週期,在一個專案中,容器不僅僅只有一個。容器之間也存在上下層關係,當一個專案中引入Spring和SpringMVC這兩個框架,其實就是2個容器,Spring是父容器,SpringMVC是其子容器,

子容器可以訪問父容器物件,而父容器不可以訪問子容器物件。(對父子屬性不成立)

該如何理解子容器可以訪問父容器物件,而父容器不可以訪問子容器物件? 舉個栗子

Web層的congtroller定義的類中,可以引用service層的物件(的介面,IC即物件),相反則不成立。

好了,接下來進入討論的關鍵:

當我們使用註解開發的時候,對於Bean 的註冊,我們使用如下的配置:

<context:component-scan base-package=“com.it.wu" />

Spring參考手冊中講到,該配置的功能是掃描預設包下的所有的@Component註解,並且自動註冊到容器(生成bean,簡化了xml檔案中配置的繁瑣工作)中,同時也掃描@Controller,@Service,@Respository這三個註解註冊他們所對應的bean到對應的容器中,因為他們是繼承自@Component。

以上的這個註解配置,使用於父類和子類容器。

當然,還有一個SpringMVC相關的配置 

      <mvc:annotation-driven />

經過驗證,這個是必須要配置的,因為它是和@RequestMapping結合使用的,這裡再補充下與SpringMVC框架相關的知識點。

處理器對映器(HandlerMapping):用來處理使用者請求的URL找到具體Controller的,有兩種方式; 
處理器介面卡(HandlerAdapter): 用來處理具體Controller對應的具體方法的,有3種;

@RequestMapping這個註解的主要目的就是對具體的Controller類或者方法進行註冊,以方便HandlerMapping用來處理請求的對映。但是@RequestMapping需要結合<mvc:annotation-driven />使用才能生效。

問題來源?

在實際的開發中,由於有了強大的註解功能,很多基於XML的配置方式已經被替代,但是在實際專案中,同時配置Spring和SpringMVC時會出現一些奇怪的異常,比如Bean被多次載入,多次例項化,或者依賴注入時,Bean不能被自動注入,但是明明你已經將該Bean註冊了。

Spring配置檔案applicationContext.xml,SpringMVC配置檔案applicationContext-MVC.xml,這樣專案中就有2個容器。

配置方式1:

applicationContext.xml中配置了<context:component-scan base-package=“com.it" />,負責所有需要註冊的Bean的掃描工作。applicationContext-MVC.xml中配<mvc:annotation-driven />,負責springMVC相關注解的使用,啟動專案發現,springMVC失效,無法進行跳轉,進行除錯,發現springMVC容器中的請求好像沒有對映到具體controller中;

 配置方式2:

將<context:component-scan base-package=“com.it" />和<mvc:annotation-driven />都配置在

applicationContext-MVC.xml中。Ok,可以執行。

為何?我用方式1.父容器進行掃描註冊所有的bean,自容器負責使用相關的註解,難道不可以嗎?檢視原始碼發現的確不可以。

方式2卻可以。原因是:

springMVC初始化時,會尋找所有當前容器中的所有@Controller註解的Bean,在方式1中,而當前容器springMVC容器中卻沒有註冊的Bean。所有的@Controller配置的Bean都註冊在Spring父容器中了。

What?難道就沒有方式1的解決方案了嗎?

答案是有的!在預設的情況下,自類容器不可以獲得父類容器的Bean,當然我們可以在子類容器中配置使用父類的容器。

在applicationContext-MVC.xml中再配置如下的一段程式碼:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">

        <property name="detectHandlerMethodsInAncestorContexts">

            <value>true</value>

        </property>

</bean>

好了,前面的兩種方式不是最完美的。

下面介紹第三種比較好的方式:

在實際工程中,會包括很多配置,根據不同的業務模組來劃分,所以我們一般思路是各負其責,明確邊界,Spring根容器負責所有其他非controller的Bean的註冊,而SpringMVC只負責controller相關的Bean的註冊。第三種方案如下:

Spring容器配置,排除所有@controller的Bean

<context:component-scan base-package="com.fsnip.open">

        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

    </context:component-scan>

SpringMVC容器配置,讓其只包括@controller的Bean

<context:component-scan base-package="com.fsnip.open" use-default-filters="false">

        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />

    </context:component-scan>

引用一下參閱的部落格的圖片。 原圖地址http://jinnianshilongnian.iteye.com/blog/1602617