在使用mybatis的時候,我們獲取dao的方式一般是這樣:
SqlSession session=sessionFactory.openSession(); PersonDao personDao=session.getMapper(PersonDao.class);
但在我們在spring的測試用例中使用mybatis的時候是這樣使用的:
PersonDao personDao=(PersonDao) context.getBean("personDao");
答案就在MapperFactoryBean這里。
Spring中獲取的名為personDao的bean,其實是與單獨使用MyBatis完成了一樣的功能,那么我們可以推斷,在bean的創建過程中一定是使用了MyBatis中的原生方法sqlSession.getMapper(PersonDao.class)進行了再一次封裝。結合配置文件,我們把分析目標轉向org.mybatis.Spring.mapper.MapperFactoryBean,初步推測其中的邏輯應該在此類中實現。查看的類層次結構圖MapperFactoryBean也實現了FactoryBean和InitializingBean接口。
MapperFactoryBean初始化
MapperFactoryBean繼承了SqlSessionDaoSupport,SqlSessionDaoSupport繼承DaoSupport,DaoSupport實現了InitializingBean接口,讓我們開看看它這接口的實現:
public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException { // Let abstract subclasses check their configuration. checkDaoConfig(); // Let concrete implementations initialize themselves. try {
//initDao()方法是模板方法,設計為留給子類做進一步邏輯處理。 initDao(); } catch (Exception ex) { throw new BeanInitializationException("Initialization of DAO failed", ex); } }
該方法主要包含兩個功能,一個是調用checkDaoConfig()方法,一個是調用initDao方法。checkDaoConfig方法在DaoSupport是抽象方法,讓我看看它在MapperFactoryBean的實現:
@Override protected void checkDaoConfig() { super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration(); if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) { try { configuration.addMapper(this.mapperInterface); } catch (Throwable t) { logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t); throw new IllegalArgumentException(t); } finally { ErrorContext.instance().reset(); } } }
該方法主要是檢查dao的配置,主要是檢驗sqlSessionFactory和mapperInterface屬性不能為空,以及檢測接口對於的映射文件是否存在,如果存在,那么就把它添加到configuration里面去,注冊mapper。
在上面的函數中,configuration.addMapper(this.mapperInterface)其實就是將PersonDao注冊到映射類型中,如果你可以保證這個接口一定存在對應的映射文件,那么其實這個驗證並沒有必要。但是,由於這個是我們自行決定的配置,無法保證這里配置的接口一定存在對應的映射文件,所以這里非常有必要進行驗證。在執行此代碼的時候,MyBatis會檢查嵌入的映射接口是否存在對應的映射文件,如果沒有回拋出異常,Spring正是在用這種方式來完成接口對應的映射文件存在性驗證。
獲取MapperFactoryBean的實例
public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); }