1. 程式人生 > >Spring與MyBatis整合優化

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屬性注入依賴。所以這就需要我們命名規範,養成良好的命名習慣。

總結

多對比幾種實現方式,選擇最好的方式!