mybatis中Mapper接口如何實例化的

關於mybatis的一個疑惑(Mapper接口如何實例化的),有須要的朋友能夠參考下。java

 

今天早上有個疑惑,在mybatis+SpringMVC的工程中,我只定義了一個接口UserMapper,而Spring就產生了一個UserMapper的對象,這個是我所不明白的,一個接口如何實例化。查了一下,發現Java 動態代理機制分析及擴展,估計mybatis也是這樣實現的。看了看mybatis的源碼,就有下文了。spring

 

本文主要跟蹤mybatis的源碼,瞭解mapper接口的動態代理對象的生成sql

 

mybatis的部分Spring配置文件以下,跟蹤其中id=」userMapper」的bean是如何建立的mybatis

 

<!-- mybatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:sqlMapConfig.xml" />
</bean>
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.tqd.dao.UserMapper"></property>
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

 

此處是經過工廠方法建立Bean 
首先咱們定位到類 org.mybatis.spring.mapper.MapperFactoryBeanapp

 

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements
        FactoryBean<T> {
    private Class<T> mapperInterface;
    private boolean addToConfig;

 

能夠看到該類實現了org.springframework.beans.factory.FactoryBean接口,經過調用 
org.mybatis.spring.mapper.MapperFactoryBean.getObject()方法來得到Beanui

 

public T getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface);
    }

 

從這個方法中,能夠看到先調用了其父類SqlSessionDaoSupport 的getSqlSession()方法,而後返回一個SqlSession對象,再調用這個對象的getMapper方法this

 

public SqlSession getSqlSession() {
        return this.sqlSession;
    }

 

在這個方法中直接返回陪父類成員變量sqlSession,sqlSession是一個接口SqlSession的對象,要找到它的實現類。在類SqlSessionDaoSupport 的代碼中spa

 

public abstract class SqlSessionDaoSupport extends DaoSupport {
    private SqlSession sqlSession;
    private boolean externalSqlSession;

public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        if (!(this.externalSqlSession))
            this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSession = sqlSessionTemplate;
        this.externalSqlSession = true;
    }

public SqlSession getSqlSession() {
        return this.sqlSession;
    }

protected void checkDaoConfig() {
        Assert.notNull(this.sqlSession,
                "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
    }
}

 

咱們能夠找到兩個方法,它們當中都包含了sqlSession的實例化代碼代理

 

public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {

        if (!(this.externalSqlSession))
            this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSession = sqlSessionTemplate;
        this.externalSqlSession = true;
}

 

根據bean的配置文件code

 

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.tqd.dao.UserMapper"></property>
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

 

Spring要將屬性sqlSessionFactory注入到MapperFactoryBean的對象中,那麼會調用setSqlSessionFactory方法,而後sqlSession 就被實例化。咱們此時確定知道 
sqlSession的實現類是org.mybatis.spring.SqlSessionTemplate,咱們定位到它的getMapper方法。

 

public <T> T getMapper(Class<T> type) {
        return getConfiguration().getMapper(type, this);
    }

 

能夠看到,它首先調用了自身的getConfiguration()方法返回一個Configuration對象,而後再調用Configuration對象的getMapper方法

 

public Configuration getConfiguration() {
        return this.sqlSessionFactory.getConfiguration();
    }

 

咱們直接定位到Configuration的getMapper方法

 

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

 

能夠看到,在這裏調用了對象mapperRegistry的getMapper方法,直接定位到該方法

 

@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null)
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

 

在這個方法裏,首先得到一個MapperProxyFactory的對象mapperProxyFactory,而後調用該對象的newInstance方法建立咱們須要的bean,定位到newInstance方法

 

public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

 

在這裏,首先構造出一個MapperProxy對象,而後調用自身的newInstance(重載的另外一個方法)方法。

 

@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

 

Bean最終在這裏建立的。關於這裏推薦你們去看下Java 動態代理機制分析及擴展

相關文章
相關標籤/搜索