spring注解與springMVC注解掃描的問題


  在將spring與springMVC結合使用時,當我們使用注解的時候,一般都是在spring配置文件中配置注解掃描dao層、service層的包,在springMVC配置文件中配置注解掃描controller,自己在練習spring+SpringMVC+mybatis的項目時對這種做法一知半解,所以在練習項目的時候在實踐中對自己的一些想法進行了驗證。

  • 一般的配置
    •   spring配置文件中
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:aop="http://www.springframework.org/schema/aop"
              xmlns:tx="http://www.springframework.org/schema/tx"
               xmlns:context="http://www.springframework.org/schema/context"   
              xsi:schemaLocation="
                  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
                  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
                  
           <!-- 啟用注解  -->
          <context:annotation-config />
      
          <!-- 設置使用注解的類所在的包 -->
          <context:component-scan base-package="dao,service.*"></context:component-scan>
          
          <bean id="propertyConfigurer"
              class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
              <property name="locations">
                  <list>
                      <value>classpath:config/jdbc.properties</value>
                  </list>
              </property>
          </bean>
          <!-- c3p0連接池配置 -->  
           <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
                 <!-- 四大參數的name不能換,和連接池的構造函數有關-->
                <property name="driverClass" value="${jdbc.driverClassName}"/>
                <property name="jdbcUrl" value="${jdbc.url}" />
                <property name="user" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />  
        
                 <!--連接池中保留的最大連接數。默認值: 15 -->   
                <property name="maxPoolSize" value="20"/>  
                <!-- 連接池中保留的最小連接數,默認為:3-->  
                <property name="minPoolSize" value="2"/>  
                <!-- 初始化連接池中的連接數,取值應在minPoolSize與maxPoolSize之間,默認為3-->  
                <property name="initialPoolSize" value="2"/>  
        
                <!--最大空閑時間,60秒內未使用則連接被丟棄。若為0則永不丟棄。默認值: 0 -->   
                <property name="maxIdleTime" value="60"/>  
                  
                <!-- 當連接池連接耗盡時,客戶端調用getConnection()后等待獲取新連接的時間,超時后將拋出SQLException,如設為0則無限期等待。單位毫秒。默認: 0 -->   
                <property name="checkoutTimeout" value="3000"/>  
                  
                <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。默認值: 3 -->   
                <property name="acquireIncrement" value="2"/>  
        
               <!--定義在從數據庫獲取新連接失敗后重復嘗試的次數。默認值: 30 ;小於等於0表示無限次-->   
                <property name="acquireRetryAttempts" value="0"/>  
        
                <!--重新嘗試的時間間隔,默認為:1000毫秒-->   
                <property name="acquireRetryDelay" value="1000" />  
        
                <!--關閉連接時,是否提交未提交的事務,默認為false,即關閉連接,回滾未提交的事務 -->   
                <property name="autoCommitOnClose" value="false"/>  
         
                <!--c3p0全局的PreparedStatements緩存的大小。如果maxStatements與maxStatementsPerConnection均為0,則緩存不生效,只要有一個不為0,則語句的緩存就能生效。如果默認值: 0-->   
                <property name="maxStatements" value="100"/>  
                <!--maxStatementsPerConnection定義了連接池內單個連接所擁有的最大緩存statements數。默認值: 0 -->   
                <property name="maxStatementsPerConnection" value="0"/>  
           </bean>
           <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
            <!-- 配置mybatis配置文件 -->
            <property name="configLocation">
               <value>classpath:config/sqlMapConfig.xml</value>
            </property>
             <!-- 實體類映射文件路徑,可以在這里直接配置,也可以在configLocation配置的文件中配置 ibatis2不支持 -->  
             <!-- <property name="mapperLocations" value="classpath:config/sqlmap/*.xml" />  -->
          </bean>
          <!-- Dao -->
          <bean id="ibatisDao" class="dao.IbatisDao">
               <property name="dataSource" ref="dataSource"></property> 
               <!-- 這里的dao繼承SqlMapClientDaoSupport,所以要顯示的配置注入 sqlMapClient-->
                <property name="sqlMapClient">
                  <ref bean="sqlMapClient"/>  
               </property>   
          </bean>
          <!-- 開啟事務注解 -->
          <tx:annotation-driven transaction-manager="transactionManager"/>
          <!-- 定義事務管理器(聲明式的事務) -->  
          <bean id="transactionManager"
              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <property name="dataSource" ref="dataSource" />
          </bean>
          
      </beans>

      這里我們配置了事務管理器和基本的dao。service層采用的是注解注入

    •  springMVC配置文件中:
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"     
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"     
              xmlns:context="http://www.springframework.org/schema/context"     
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd   
             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
      
      <!--     啟用spring mvc 注解 -->
          <context:annotation-config />
      
          <!-- 設置使用注解的類所在的包 -->
         <context:component-scan base-package="controller"></context:component-scan>   
           
          <!-- 完成請求和注解POJO的映射  3.1后已經過時 與DefaultAnnotationHandlerMapping配套使用
          <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />-->
          <!-- 新的注解映射-->
          <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
          
          
           <!-- 使用新的注解映射必須指定 RequestMappingHandlerMapping去替代過時的DefaultAnnotationHandlerMapping-->
           <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
           <!-- 使用ajax向前台返回json需要在注解映射中添加轉換器 -->
           <!-- 依賴包為jackson-core 、 jackson-annotation、 jackson-databind -->
           <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
                    <property name="messageConverters">
                        <list>
                            <ref bean="jsonHttpMessageConverter"/>
                        </list>
                    </property>
          </bean>
      <bean id="jsonHttpMessageConverter" 
          class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /><!--   用於jackson2 -->
           <!--  class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/> -->
          
          <!-- 對轉向頁面的路徑解析。prefix:前綴, suffix:后綴 -->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/page/" p:suffix=".jsp" />
      </beans>

      springMVC配置文件中配置了指定的HandlerAdapter和HandlerMapping以及Resolver。
      在這種配置下,項目能正常運行,配置了@Transactional的service中的事務也能被我們的事務管理器管理。

  • 只在spring配置文件中啟用注解掃描(關閉springmvc掃描),掃描dao、service、controller。
      這種情況下,項目啟動正常,但是無法處理我們的請求,鑒於springmvc容器是spring容器的子容器,我猜想由於controller中的所有請求處理方法我都是采用@requestMapping來進行配置的,requestMapping都是由我們的springMVC配置文件中配置的HandlerAdapter和HandlerMapping以及Resolver的Bean來進行處理(即使我們不在這里面配置,spingmvc也有默認的),但是父容器又不能訪問子容器的bean,所以即使掃描了controller包也無法將controller的處理方法與我們的請求正確mapping,所以這里如果僅僅在spring中掃描所有包,項目是無法實現正常運轉的。
  • 只在spring配置文件中啟用注解掃描,掃描dao、service、controller,並且在spring配置文件中配置springmvc的HandlerAdapter和HandlerMapping以及Resolver。
      這種情況項目與我們一般配置的效果一樣,這種情況就相當於我們在spring中也完成了spingmvc的配置,將原本應該在springmvc容器中的bean直接在spring中配置,雖然效果是一樣的,但是不建議這種做。這種配置的結果也代表我們上一種情況出現的原因的猜想是對的,spring父容器無法訪問springmvc中的bean,無法將掃描到的controller與請求url正確適配。
  • 在springMVC配置文件中啟用注解掃描(關閉spring掃描),掃描dao、service、controller。
      這種情況下項目能正常跳轉,但是我們通過@Transactional配置的service事務失效,這里是因為spring容器配置了事務管理器后,裝配的service都是經過cglib代理過的實例,具有事務功能,而springmvc容器裝配的service是沒有進行代理處理的,所以是沒有事務功能的,這一點可以參見這篇博客http://blog.csdn.net/haoyifen/article/details/51172647。這里我試着在springMVC配置文件中也配置了一個事務管理器過后,發現一切正常了,由springmvc裝配的service同樣也具備事務功能,這里就很奇怪,為什么父容器配置的事務管理器子容器無法使用呢?父容器中的bean子容器都是可以訪問的,為什么沒有使用呢?
    到這里差不多可以回答開始的問題了,為什么要在spring中掃描dao、service,因為通過spring容器掃描dao以及service可以進行事務的增強,如果你僅僅在一個子容器中進行事務的增強那么其他的serviceBean是不會被事務增強的(比如第四種情況中,如果我們在spring容器中手動配置一個bean,那么這個bean不是由springmvc裝配的,而我們的事務管理器在springmvc中,這個bean就不具備事務的功能)。而controller之所以要在springmvc中配置,因為spring容器無法訪問到springmvc容器的bean(HandlerAdapter和HandlerMapping以及Resolver等),無法完成請求與hander的正確適配,如果要強行實現,在spring中配置HandlerAdapter和HandlerMapping以及Resolver則顯得太過牽強。在書上看到的一種說法是這樣也體現了分層的概念,dao、service等web層都需要使用的bean應該直接在spring容器中裝配,而controller這種則放在專門處理請求跳轉的springmvc容器中,相對於將所有bean配置在spring容器中,也體現了權限控制的思想吧。

 


免責聲明!

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



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