原文地址:http://www.cnblogs.com/fangjian0423/p/spring-mybatis-MapperScannerConfigurer-analysis.html

前言

本文将分析mybatis与spring整合的MapperScannerConfigurer的底层原理,之前已经分析过java中实现动态,可以使用jdk自带api和cglib第三方库生成动态代理。本文分析的mybatis版本3.2.7,mybatis-spring版本1.2.2。

MapperScannerConfigurer介绍

MapperScannerConfigurer是spring和mybatis整合的mybatis-spring jar包中提供的一个类。

想要了解该类的作用,就得先了解MapperFactoryBean

MapperFactoryBean的出现为了代替手工使用SqlSessionDaoSupport或SqlSessionTemplate编写数据访问对象(DAO)的代码,使用动态代理实现。

比如下面这个官方文档中的配置:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />

<property name="sqlSessionFactory" ref="sqlSessionFactory" />

</bean>

org.mybatis.spring.sample.mapper.UserMapper是一个接口,我们创建一个MapperFactoryBean实例,然后注入这个接口和sqlSessionFactory(mybatis中提供的SqlSessionFactory接口,MapperFactoryBean会使用SqlSessionFactory创建SqlSession)这两个属性。

之后想使用这个UserMapper接口的话,直接通过spring注入这个bean,然后就可以直接使用了,spring内部会创建一个这个接口的动态代理。

当发现要使用多个MapperFactoryBean的时候,一个一个定义肯定非常麻烦,于是mybatis-spring提供了MapperScannerConfigurer这个类,它将会查找类路径下的映射器并自动将它们创建成MapperFactoryBean。

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="org.mybatis.spring.sample.mapper" />

</bean>

这段配置会扫描org.mybatis.spring.sample.mapper下的所有接口,然后创建各自接口的动态代理类。

注意:这里会扫描下面所有的接口,但是经过我的实验,只会对在mapper.xml中的namespace中配置了的接口才会生成动态代理类。不会影响到basePackage下面的其他接口。

MapperScannerConfigurer底层代码分析

以以下代码为示例进行讲解(部分代码,其他代码及配置省略):

package org.format.dynamicproxy.mybatis.dao;

public
interface
UserDao {

public User getById(int id);

public
int
add(User user);

public
int
update(User user);

public
int
delete(User user);

public List<User> getAll();

}

 

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="org.format.dynamicproxy.mybatis.dao"/>

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>

</bean>

我们先通过测试用例debug查看userDao的实现类到底是什么。

我们可以看到,userDao是1个MapperProxy类的实例。
看下MapperProxy的源码,没错,实现了InvocationHandler,说明使用了jdk自带的动态代理。

public
class
MapperProxy<T> implements
InvocationHandler, Serializable {

 

private
static
final
long serialVersionUID = -6424540398559729838L;

private
final SqlSession sqlSession;

private
final Class<T> mapperInterface;

private
final Map<Method, MapperMethod> methodCache;

 

public
MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {

this.sqlSession = sqlSession;

this.mapperInterface = mapperInterface;

this.methodCache = methodCache;

}

 

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if (Object.class.equals(method.getDeclaringClass())) {

try {

return method.invoke(this, args);

} catch (Throwable t) {

throw ExceptionUtil.unwrapThrowable(t);

}

}

final MapperMethod mapperMethod = cachedMapperMethod(method);

return mapperMethod.execute(sqlSession, args);

}

 

private MapperMethod cachedMapperMethod(Method method) {

MapperMethod mapperMethod = methodCache.get(method);

if (mapperMethod == null) {

mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());

methodCache.put(method, mapperMethod);

}

return mapperMethod;

}

 

}

 

注:了解概念看到这里就可以了,如果需要详细研究可以继续看下面的内容。

 

下面开始分析MapperScannerConfigurer的源码

MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor接口是一个可以修改spring工长中已定义的bean的接口,该接口有个postProcessBeanDefinitionRegistry方法。

然后我们看下ClassPathMapperScanner中的关键是如何扫描对应package下的接口的。

其实MapperScannerConfigurer的作用也就是将对应的接口的类型改造为MapperFactoryBean,而这个MapperFactoryBean的属性mapperInterface是原类型。MapperFactoryBean本文开头已分析过。

所以最终我们还是要分析MapperFactoryBean的实现原理!

MapperFactoryBean继承了SqlSessionDaoSupport类,SqlSessionDaoSupport类继承DaoSupport抽象类,DaoSupport抽象类实现了InitializingBean接口,因此实例个MapperFactoryBean的时候,都会调用InitializingBean接口的afterPropertiesSet方法。

DaoSupport的afterPropertiesSet方法:

MapperFactoryBean重写了checkDaoConfig方法:

然后通过spring工厂拿对应的bean的时候:

这里的SqlSession是SqlSessionTemplate,SqlSessionTemplate的getMapper方法:

Configuration的getMapper方法,会使用MapperRegistry的getMapper方法:

MapperRegistry的getMapper方法:

MapperProxyFactory构造MapperProxy:

没错! MapperProxyFactory就是使用了jdk组带的Proxy完成动态代理。
MapperProxy本来一开始已经提到。MapperProxy内部使用了MapperMethod类完成方法的调用:

下面,我们以UserDao的getById方法来debug看看MapperMethod的execute方法是如何走的。

@Test

public
void
testGet() {

int id = 1;

System.out.println(userDao.getById(id));

}

<select id="getById" parameterType="int" resultType="org.format.dynamicproxy.mybatis.bean.User">

SELECT * FROM users WHERE id = #{id}

</select>


mybatic MapperScannerConfigurer的原理的更多相关文章

  1. MapperScannerConfigurer的原理

    原文地址:http://www.mybatis.org/spring/zh/mappers.html#MapperScannerConfigurer 为了代替手工使用 SqlSessionDaoSup ...

  2. Mybatis的体系结构(转载)

    原文:http://blog.csdn.net/hupanfeng/article/details/9068003/ MyBatis的前身叫iBatis,本是apache的一个开源项目, 2010年这 ...

  3. java动态代理浅析

    最近在公司看到了mybatis与spring整合中MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 于是想起了java的动态代理,然后就有了这篇文章 ...

  4. Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析

    前言 本文将分析mybatis与spring整合的MapperScannerConfigurer的底层原理,之前已经分析过java中实现动态,可以使用jdk自带api和cglib第三方库生成动态代理. ...

  5. 转:Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析

    原文地址:Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析 前言 本文将分析mybatis与spring整合的MapperScannerConfigur ...

  6. MapperScannerConfigurer

    MapperScannerConfigurer转自:http://www.cnblogs.com/fangjian0423/p/spring-mybatis-MapperScannerConfigur ...

  7. 170111、MapperScannerConfigurer处理过程源码分析

    前言 本文将分析mybatis与spring整合的MapperScannerConfigurer的底层原理,之前已经分析过java中实现动态,可以使用jdk自带api和cglib第三方库生成动态代理. ...

  8. ssm框架搭建流程及原理分析

    这几天自己想搭建个ssm框架玩一下,有些东西长时间不玩都给忘了,所以自己把整个流程整理了一下,只要跟着步骤,就能顺利完成ssm框架的搭建. 一.搭建步骤: 1.整理jar包     2.对于一个web ...

  9. 2017.2.9 深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二)-----配置文件详解

    深入浅出MyBatis技术原理与实践-第八章 MyBatis-Spring(二) ------配置文件详解 8.2 MyBatis-Spring应用 8.2.1 概述 本文主要讲述通过注解配置MyBa ...

随机推荐

  1. [转帖]nginx配置ssl证书实现https访问

    https://www.cnblogs.com/tianhei/p/7726505.html 今天就是如此处理的 感觉挺不错的. 一,环境说明 服务器系统:ubuntu16.04LTS 服务器IP地址 ...

  2. 【Java学习】类、对象、实例—类是对象的抽象,对象是类的实例

    类.对象.实例的关系是什么,如果不能很好的理解什么是类什么是对象就无法讲清楚, 类:某种事物与另一种事物具有相似性,比如哈士奇和泰迪,我们发现他们有一些相似的特性和行为,在生物学上,他们都属于“狗”, ...

  3. 【hash】Three friends

    [来源]:bzoj3916 [参考博客] BZOJ3916: [Baltic2014]friends [ 哈希和哈希表]Three Friends [Baltic2014][BZOJ3916]frie ...

  4. Jmeter之Linux安装(Xshell),分布式运行Linux作为slave机

    甲方爸爸要求,用Linux压测......   所以在公司服务器Linux上搭建Jmeter 但实际一个Jmeter程序也有程序瓶颈~ 所以在Jmeter瓶颈下,搭建分布式压测系统.(也许可以尝试在一 ...

  5. 基于C#实现与JY61姿态角度传感器通信

    产品介绍:  此六轴模块采用高精度的陀螺加速度计 MPU6050,通过处理器读取 MPU6050 的测量数据 然后通过串口输出,免去了用户自己去开发 MPU6050 复杂的 IIC 协议,同时精心的 ...

  6. python增量爬虫

    import pymysql def insert_db(db_table, issue, time_str, num_code): host = '127.0.0.1' user = 'root' ...

  7. 原生html、js手写 radio与checkbox 美化

    原生html.js手写 radio与checkbox   美化 html <!DOCTYPE html> <html> <head> <meta charse ...

  8. spring整合shiro配置BUG,Tomcat启动不了:Error during artifact deployment. See server log for details

    现象 spring配置shiro权限控制之后,项目无法启动 [2019-08-09 09:00:35,800] Artifact export_web_manager:war exploded: Er ...

  9. 2 java开发环境的配置步骤

    1  首先需要下载JDK(以java se development kit java标准版开发包) 8.0 如果只是单纯的运行java程序则只需要安装JRE(java runtime envirome ...

  10. ASE19 团队项目 模型组 scrum report集合

    scrum report 链接 scrum1 report scrum2 report scrum3 report scrum4 report scrum5 report scrum6 report ...