spring-mybatis 整合原理剖析

本文详细剖析了Spring-Mybatis整合的原理,包括SqlSessionFactoryBean的作用,@MapperScan的实现,以及如何自定义整合流程。通过解析配置、接口扫描、MapperFactoryBean的配置等方面,展示了Spring如何管理和实例化Mybatis的Mapper接口。
摘要由CSDN通过智能技术生成

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进一步的配置;
在这里插入图片描述
这个方法篇幅较长,就不上代码了 大家可以自己跟进一下;
主要做了以下几件事:

  1. 拿到beanDefnition 的Class类型, 并且替换成 MapperFactoryBean.class;
  2. 设置MapperFactoryBean 中的初始化参数为当前接口的ClassName;
  3. 设置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.运行自己实现的整合,得到正确结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值