文档章节

mybatis中Mapper接口如何实例化的

梦蝶飘雪
 梦蝶飘雪
发布于 2017/02/16 16:35
字数 844
阅读 79
收藏 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 动态代理机制分析及扩展

本文转载自:http://www.aichengxu.com/java/68780.htm

共有 人打赏支持
梦蝶飘雪
粉丝 4
博文 26
码字总数 7682
作品 0
东城
程序员
spring中的mybatis(1)

开门见山 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="cl......

hyssop
2015/10/29
0
0
Mybatis学习系列(七)缓存机制

Mybatis缓存介绍 MyBatis提供一级缓存和二级缓存机制。 一级缓存是Sqlsession级别的缓存,Sqlsession类的实例对象中有一个hashmap用于缓存数据。不同的Sqlsession实例直接hashmap互不影响。M...

仍是少年
07/12
0
0
Mybatis-spring整合源码解析

原文:http://my.oschina.net/doctor2014/blog/411594 Mybatis整合spring,主要通过两种途径:一种是基于xml配置的,一种基于java config 配置。 一种是基于xml配置的。这种方式通过解析xml...

Beaver_
2015/05/07
1K
0
Mybatis3.3.x技术内幕(二):动态代理之投鞭断流(自动映射器Mapper的底层实现原理)

一日小区漫步,我问朋友:Mybatis中声明一个interface接口,没有编写任何实现类,Mybatis就能返回接口实例,并调用接口方法返回数据库数据,你知道为什么不?朋友很是诧异:是啊,我也很纳闷...

祖大俊
2016/04/26
2.4K
12
就是让你懂Spring中Mybatis的花样配置

一、前言 Mybatis作为一个优秀的存储过程和高级映射的持久层框架,目前在项目实践中运用的比较广泛,最近做项目时候发现了一种之前没见过的配置方式,这里总结下常用的配置方式以便备忘查找。...

今天你不奋斗明天你就落后
2017/09/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring IOC实现原理

1、BeanDefinition 对依赖翻转模式中管理对象依赖关系的数据抽象 实现依赖翻转功能的核心数据结构 依赖翻转功能都是围绕对BeanDefinition 处理完成的 有了这些BeanDefinition 基础数据结构,...

职业搬砖20年
15分钟前
0
0
Python判断变量的数据类型的两种方法

1、isinstance(变量名,类型) def varargsql(self, sql, *args): if isinstance(args, tuple): self.cursor.execute(sql, args) self.conn.commit() 2、通过与其他已......

fang_faye
15分钟前
0
0
xml 转义特殊字符

XML中共有5个特殊的字符,分别是:&<>“’。如果配置文件中的注入值包括这些特殊字符,就需要进行特别处理。有两种解决方法:其一,采用本例中的特殊标签,将包含特殊字符的字符串封装起来;...

inidcard
17分钟前
0
0
Mysql中哪些sql 不会走索引

1. 索引列参与了计算 SELECT `sname` FROM `stu` WHERE `age`+10=30; 2. 索引使用了函数运算 SELECT `sname` FROM `stu` WHERE LEFT(`date`,4) <1990; 3. like SELECT * FROM `houdunwang` W......

ChyiHuang
26分钟前
1
0
nginx 504 Gateway Time-out

打开nginx.config: 参数介绍: #设定http服务器http{include mime.types; #文件扩展名与文件类型映射表default_type application/octet-stream; #默认文件类型#charset utf-8; #默...

lyle_luo
28分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部