mybatis中Mapper接口如何实例化的
mybatis中Mapper接口如何实例化的
梦蝶飘雪 发表于9个月前
mybatis中Mapper接口如何实例化的
  • 发表于 9个月前
  • 阅读 53
  • 收藏 0
  • 点赞 0
  • 评论 0

关于mybatis的一个疑惑(Mapper接口如何实例化的),有需要的朋友可以参考下。

 

今天早上有个疑惑,在mybatis+SpringMVC的工程中,我只定义了一个接口UserMapper,而Spring就产生了一个UserMapper的对象,这个是我所不明白的,一个接口如何实例化。查了一下,发现Java 动态代理机制分析及扩展,估计mybatis也是这样实现的。看了看mybatis的源码,就有下文了。

 

本文主要跟踪mybatis的源码,了解mapper接口的动态代理对象的生成

 

mybatis的部分Spring配置文件如下,跟踪其中id=”userMapper”的bean是如何创建的

 

    <!-- 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.MapperFactoryBean

 

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()方法来获得Bean

 


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

 

从这个方法中,可以看到先调用了其父类SqlSessionDaoSupport 的getSqlSession()方法,然后返回一个SqlSession对象,再调用这个对象的getMapper方法

 

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

 

在这个方法中直接返回陪父类成员变量sqlSession,sqlSession是一个接口SqlSession的对象,要找到它的实现类。在类SqlSessionDaoSupport 的代码中

 

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的配置文件

 

<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 动态代理机制分析及扩展

共有 人打赏支持
粉丝 5
博文 24
码字总数 7544
×
梦蝶飘雪
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: