回顾一下Mybatis的Mapper接口实例的生成与执行流程
众所周知,我们基于MyBatis 操作数据库,实际上就是通过 SqlSession 获取一个 JDBC 连接调用api来操作。
1、SqlSession接口。SqlSession 接口有常用的实现类有:DefaultSqlSession(线程不安全)、SqlSessionTemplate (spring中线程安全类,接下来的主角)
/*
* The default implementation for {@link SqlSession}.
* Note that this class is not Thread-Safe.
*
* @author Clinton Begin
*/
public class DefaultSqlSession implements SqlSession {
}
2、我们通过sqlsession获取mapper接口实例的基本过程如下:
通过SqlSession的getMapper(type)方法获取的Mapper接口实例,这个实例是通过MapperProxyFactory生成的代理实例MapperProxy同时实现了invocationhandler接口。
3、MapperProxy的方法执行,在它的invoke方法中调用SqlSession的具体api来执行的。
public class MapperProxy<T> implements InvocationHandler, Serializable {
//通过传入的sqlsession进行方法调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
这个过程用到JDK的动态代理设计模式。
今天的问题:
问题1、spring整合mybatis后是如何把Mapper代理对象注入ioc容器的呢?
- 基于注解@MapperScan和@Mapper,前者是spring的注解,后者是mybatis的注解
- 基于Xml配置文件
今天我们讨论的是基于@MapperScan注解的方式!
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
我们通过@MapperScan(“com.xxx.xxx”)扫描package把Mapper接口生成实例并注入IOC容器。扫描注册的类就是通过MapperScannerRegistrar.class实现的!
- MapperScannerRegistrar.class
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
/**
- {@inheritDoc}
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
BeanDefinitionRegistry registry, String beanName) {
//获取MapperScannerConfigurer.class的BeanDefinitionBuilder
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
builder.addPropertyValue("processPropertyPlaceHolders", true);
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
builder.addPropertyValue("annotationClass", annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
builder.addPropertyValue("markerInterface", markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
}
String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
if (StringUtils.hasText(sqlSessionTemplateRef)) {
builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
}
String sqlSessionFactoryRef = annoAttrs.ge