為啥Spring和Spring MVC包掃描要分開?


背景:

      最近在搭建新工程的時候發現有些Spring的配置不是很了解,比如Spring 配置里面明明配置了component-scan,為啥Spring MVC配置文件還需要配置一下,這樣豈不是多此一舉?由於以前基本是在現有的工程上直接開發或者別的工程的配置文件直接拷貝過來,所以也沒太關注這個問題。出於好奇,谷歌了一下發現原來這個里面大有學問呢,詳情請見下文。正常代碼如下:

 

Xml代碼   收藏代碼
  1. <!-- spring 配置文件-->  
  2. <context:component-scan base-package="com.xxx.xxx.account.front">  
  3.      <context:exclude-filter type="annotation"   
  4.          expression="org.springframework.stereotype.Controller" />  
  5. </context:component-scan>  
  6.   
  7. <!-- spring mvc -->     
  8. <context:component-scan base-package="com.xxx.xxx.account.front.web" use-default-filters="false">  
  9.     <context:include-filter type="annotation"   
  10.         expression="org.springframework.stereotype.Controller" />  
  11. </context:component-scan>  

    

    測試bean

Java代碼   收藏代碼
  1. @Service  
  2. public class TestService implements InitializingBean {   
  3.   
  4.     @Autowired  
  5.     private PersonalAddressAjaxController personalAddressAjaxController;  
  6.   
  7.     @Override  
  8.     public void afterPropertiesSet() throws Exception {  
  9.         System.out.println("--------------------------------");  
  10.     }  
  11. }  

 

    原理:   

      原來Spring 是父容器, Spring MVC是子容器, 子容器可以訪問父容器的bean,父容器不能訪問子容器的bean。 

     具體參照:

      Spring和SpringMVC父子容器關系初窺

      Spring為什么不做全局包掃描

      Spring與SpringMVC的容器關系分析

 

    測試一: Spring加載全部bean,MVC加載Controller

Xml代碼   收藏代碼
  1. <!-- spring 配置文件-->  
  2. <context:component-scan base-package="com.xxx.xxx.account.front">  
  3. </context:component-scan>  
  4.   
  5. <!-- spring mvc -->     
  6. <context:component-scan base-package="com.xxx.xxx.account.front.web" use-default-filters="false">  
  7.     <context:include-filter type="annotation"   
  8.         expression="org.springframework.stereotype.Controller" />  
  9. </context:component-scan>  

    

    測試結果:TestService通過,界面顯示正常。

    原因:父容器加載了全部bean,所以Service 能訪問到Controller。MVC容器默認查找當前容器,能查到有轉發的Controller規則所以界面正常跳轉。

 

    測試二:Spring加載全部Bean,MVC容器啥也不加載

Xml代碼   收藏代碼
  1. <!-- spring 配置文件-->  
  2. <context:component-scan base-package="com.xxx.xxx.account.front">  
  3. </context:component-scan>  
  4.   
  5. <!-- spring mvc -->     
  6. 無  

    測試結果:TestService通過,界面顯示404。

    原因:父容器加載了全部bean,所以Service 能訪問到Controller。MVC容器默認查找當前容器的Controller,找不到所以界面出現404。

 

   測試三:Spring加載所有除了Controller的bean,MVC只加載Controller

Xml代碼   收藏代碼
  1. <!-- spring 配置文件-->  
  2. <context:component-scan base-package="com.xxx.xxx.account.front">  
  3.      <context:exclude-filter type="annotation"   
  4.          expression="org.springframework.stereotype.Controller" />  
  5. </context:component-scan>  
  6.   
  7. <!-- spring mvc -->     
  8. <context:component-scan base-package="com.xxx.xxx.account.front.web" use-default-filters="false">  
  9.     <context:include-filter type="annotation"   
  10.         expression="org.springframework.stereotype.Controller" />  
  11. </context:component-scan>  

    測試結果:TestService初始化失敗,如果注釋掉該bean,界面正常。

    原因:父容器不能訪問子容器的bean。

 

    測試四:Spring不加載bean,MVC加載所有的bean

Xml代碼   收藏代碼
  1. <!-- spring 配置文件-->  
  2. 無  
  3.   
  4. <!-- spring mvc -->     
  5. <context:component-scan base-package="com.xxx.xxx.account.front.web" use-default-filters="true">  
  6. </context:component-scan>  

    測試結果:TestService通過,界面正常。

    原因:因為所有的bean都在子容器中,也能查到當前容器中的Controller,所以沒啥問題。

 

 

    疑問一: 單例的bean在父子容器中存在一個實例還是兩個實例?

    答:初始化兩次,Spring 容器先初始化bean,MVC容器再初始化bean,所以應該是兩個bean。

 

    疑問二:為啥不把所有bean 都在子容器中掃描?

    答: 網上很多文章說子容器不支持AOP,其實這是不對的。因為正常會有AOP的相關配置都在Spring容器中配置,如果都遷移到MVC配置文件,則所有bean都在子容器中,相當於只有一個容器了,所以也就實現了AOP。缺點是不利於擴展。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM