spring-mybatis的基本使用
1.创建mapper接口,mapper.xml文件
2.配置相关信息,配置如下图
3.调用
SqlSessionFactoryBean
SqlSessionFactoryBean 实现了 FactoryBean, InitializingBean 这两个接口; 依据对Spring的了解,去观察相关的方法;
getObject() 返回了一个SqlSessionFactory的实例, 那么我们可以断定这个类就是用来生成SqlSessionFactory对象的了;
在Bean的生命周期回调中,对sqlSessionFactory 进行了设置; 比如 DataSource, confingLocations, mapperLocations 等等;
@MapperScan
使用Import注解加入了一个类,通过对Spring的了解; 可以梳理出在解析 AppConfig配置类时,解析到Import注解时会去处理; 这个类实现了ImportBeanDefinitionRegistrar 接口, 这个接口可以手动的注册BeanDefinition到Spring容器中, 我们去看它的接口实现;
注册了一个MapperScannerConfigurer 类型的beanDefinition; 这个类实现了 BeanDefinitionRegistryPostProcessor 接口,去找对应的方法 postProcessBeanDefinitionRegistry() 实现;
这个方法主要是创建了一个扫描器,将我们传入路径下的文件扫描成BeanDefinition 加入到Spring容器中;
这里mybatis 使用了Spring自带的扫描器,节省了大部分的工作;
mybatis 这里通过继承使用Spring的扫描器,但是重写了判断条件,这里只有接口才能通过筛选;
当调用到scanner.scan() 方法时,会调用到父类的scan方法, 父类又会调用doScan()方法; 这里mybatis重写了doScan方法的逻辑; 将扫描得到的BeanDefinition进一步的配置;
这个方法篇幅较长,就不上代码了 大家可以自己跟进一下;
主要做了以下几件事:
- 拿到beanDefnition 的Class类型, 并且替换成 MapperFactoryBean.class;
- 设置MapperFactoryBean 中的初始化参数为当前接口的ClassName;
- 设置MapperFactoryBean 中的其他属性, 主要的属性有sqlSessionFactory;
MapperFactoryBean 中有两个重要的属性,
一个是mapperInterface,对应着我们的mapper接口类型;
另一个是sqlSessionTemplate,在它的父类里面,可以openSession();
这里主要是用到了Spring推断构造方法的原理:
首先修改BeanDefinition的Class类型为MapperFactoryBean, 并且设置了初始化参数 mapperInterface=mapper接口; 设置了自动注入的类型为 by_type;
技术点:spring在推断构造方法时,由于我们已经制定了其中一个参数,所以Spring一定会使用一个有参构造函数; 设置自动注入类型为by_type, 那么在Spring进行属性填充时 就会根据set方法的参数类型 从Spring容器中获取;
自己实现spring整合mybatis
mybatis的整合代码比较多; 我自己写了一个简单的 足以诠释原理;
dataSource, sqlSessionFactoryBean 还是使用mybatis提供的; 我们只开发整合的流程代码;
1.自定义@MapperScan注解
2.开发import 类
3.开发扫描类
重写isCandidateComponent , doScan 方法;
public class JtfuScan extends ClassPathBeanDefinitionScanner {
public JtfuScan(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
return metadataReader.getClassMetadata().isInterface();
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
processBeanDefinitions(beanDefinitionHolders);
return beanDefinitionHolders;
}
public void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitionHolders){
for (BeanDefinitionHolder holder : beanDefinitionHolders) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = beanDefinition.getBeanClassName();
beanDefinition.setBeanClass(MapperFactoryBean.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
}
}
}
4.自定义mapperFactoryBean
public class MapperFactoryBean<T> implements FactoryBean<T> {
private Class mapperInterface;
private SqlSessionFactory sqlSessionFactory;
public MapperFactoryBean() {
}
public MapperFactoryBean(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public T getObject() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
return (T) sqlSession.getMapper(mapperInterface);
}
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
public SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
}
5.运行自己实现的整合,得到正确结果