Spring与Mybatis结合的MapperScannerConfigurer处置过程源码剖析转载
原创本文将分析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)的代码,使用动态代理实现。
例如,本官方文档中的以下配置:
org.mybatis.spring.sample.mapper.UserMapper是一个接口,我们创建一个MapperFactoryBean实例,然后注入此接口和。sqlSessionFactory(mybatis中提供的SqlSessionFactory接口,MapperFactoryBean会使用SqlSessionFactory创建SqlSession)这两个属性。
之后要使用此UserMapper接口,直接通过spring注入这个bean,然后您可以直接使用它,spring此接口的动态代理是在内部创建的。
当您发现要使用多个MapperFactoryBean同时,一个定义肯定很麻烦,所以mybatis-spring提供了MapperScannerConfigurer这个类将在类路径下查找映射器并自动创建它们MapperFactoryBean。
此配置扫描org.mybatis.spring.sample.mapper然后为每个接口创建一个动态代理类。
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 getAll();
}
让我们先看看测试用例debug查看userDao实现类到底是什么。
我们可以看到,userDao是1个MapperProxy类的实例。
看下MapperProxy源代码,是的,已实现InvocationHandler,表示使用jdk自包含的动态代理。
public class MapperProxy implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class mapperInterface;
private final Map methodCache;
public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map 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));
}
示例代码: https://github.com/fangjian0423/dynamic-proxy-mybatis-study
总结
来到新公司,联系Mybatis,之前联系~ 但接触不深,突然发现spring与mybatis集成后,您只能编写接口而不实现它,spring默认值将帮助我们实现它,然后感觉非常神奇,所以我写了一篇文章。 java动态代码分析 和本文。
参考资料
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除