Spring與MyBatis整合優化
前言
在上一篇文章中,我們使用了老老實實的方式對兩個框架進行了整合,我們在每一個服務層元件都聲明瞭一個SqlSessionTemplate物件,在呼叫資料層的時候通過getMapper()方法對映得到某個介面,然後呼叫裡面的方法。
直接在業務元件呼叫getMapper()方法並不是最佳選擇,每一次呼叫這個方法就會做一次反射。mybatis-spring整合包中提供了相關元件,可以不必每次都呼叫getMapper()方法,而是通過配置的方式直接為業務物件注入對映器實現。接下來我們就對整合做一下優化。
優化前的要求
1、對映的名稱空間(即對映檔案的名稱空間)要與對映器介面的包路徑對應;
2、對映元素的id必須和對映器介面的方法名一致。
3、以下程式碼、修改都是基於上一篇博文的,各位可以先看一下上一篇博文的目錄結構以及裡面的程式碼,因為只需要在一些地方做修改,沒必要再把所有程式碼都拿過來。
開始優化
第一種優化——使用MapperFactoryBean注入對映器
我們不再在服務層實現類中定義SqlSessionTemplate物件,而是定義它所依賴的介面,此處以UserServiceImpl為例。所需要的程式碼、以及目錄結構與上一篇博文都一樣,沒有程式碼的朋友可以去上一篇博文找程式碼,或者自己擼。
package com.Blog.ServiceImpl; import com.Blog.Dao.StudentDao; import com.Blog.Entity.Student; import com.Blog.Service.StudentService; import org.apache.ibatis.annotations.Param; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Service("studentService") //使用註解定義服務層Bean,可以刪除配置檔案中的配置 public class StudentServiceImpl implements StudentService { @Autowired @Qualifier("studentDao") private StudentDao studentDao; //所依賴的Dao層介面 @Override public Student getStudent(@Param("id") int id) { return studentDao.getStudent(id); } }
因為我們用註解的方式定義了Service層的一個Bean,所以可以將之前在配置檔案中定義的id為studentService的Bean刪除了。又因為我們不再顯式直接使用SqlSessionTemplate物件,所以也可進行刪除。綜上,我們需要在spring-mybatis.xml中做的操作:
刪除第三步、第四步,並在第二步之後加上以下程式碼:
<!--定義一個Bean,類即是org.mybatis.spring.mapper.MapperFactoryBean,指定它裡面的mapperInterface是我們要指向的介面--> <bean id="studentDao" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.Blog.Dao.StudentDao" /> <property name="sqlSessionFactory" ref="factory" /> </bean>
因為我們是用註解定義的元件,所以不要忘了掃描我們的包:
<context:component-scan base-package="com.Blog.ServiceImpl" />
其他的都不需要動,執行測試類,是沒有問題的。
那麼MapperFactoryBean到底是一個什麼東西呢?
MapperFactoryBean是SqlSessionDaoSupport的子類,需要通過一個SqlSessionFactory例項來建立SqlSessionTemplate例項,所以我們為其注入了一個id為factory的Bean元件。這個類還有一個屬性是mapperInterface屬性,即對映器介面,我們只需要指定為要對映的介面的路徑,就相當於呼叫了getMapper()方法反射得到這個介面的資訊。最後我們在StudentServiceImpl類中通過註解的方式為studentDao屬性注入依賴,就可以呼叫相關的方法了。
需要注意的是,如果對映器對應的SQL對映檔案與對映器的類路徑相同,那麼該對映檔案可以自動被MapperFactoryBean解析,在配置SqlSessionFactoryBean時可以不用mapperLocations屬性來掃描SQL對映檔案。反之,仍然需要進行掃描引入。因為我們定義的介面和對應的對映檔案不在同一包下,名稱也不一樣,所以我們還是手動掃描了。
第二種——使用MapperScannerConfigurer注入對映器
在上面的優化中,我們使用MapperFactoryBean對對映器進行配置,簡化了DAO模組的編碼。但是,如果有多個介面,即需要配置多個對映器的時候,相應的配置項就會變得很多。為了簡化配置工作量,mybatis-spring整合包中提供了MapperScannerConfigurer,它可以掃描指定包中的介面,併為它們直接註冊為MapperFactoryBean。
將第一種優化中配置MapperFactoryBean的程式碼替換為以下程式碼:
<!--使用MapperScannerConfigurer掃描指定包的介面,並自動生成MapperFactoryBean-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.Blog.Dao" />
</bean>
執行也是沒問題的。
basePackage屬性中可以指定多個包,用逗號或分號隔開;
MapperScannerConfigurer會為所有由它建立的對映器開啟自動裝配。也就是說我們不用顯式注入SqlSessionFactory例項,它會自動從容器中掃描。如果容器中有多個SqlSessionFactory例項,此時需要顯式指定所依賴的SqlSessionFactory,如下
<!--使用MapperScannerConfigurer掃描指定包的介面,並自動生成MapperFactoryBean-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="factory" />
<property name="basePackage" value="com.Blog.Dao" />
</bean>
對映器被注入到容器中之後,Spring會根據其介面名稱為其命名,規則是首字母小寫的非完全限定類名。例如StudentDao介面,會被命名為studentDao,所以我們可以直接在StudentServiceImpl中為studentDao屬性注入依賴。所以這就需要我們命名規範,養成良好的命名習慣。
總結
多對比幾種實現方式,選擇最好的方式!