Mybatis
Mybatis和Spring的整合:
- @MapperScan注解通过@Import方法导入MapperScannerRegistrar类,MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,覆写了registerBeanDefinitions方法,作用为手动注册某个Bean的BeanDefinition到容器中【DefaultListableBeanFactory=>beanDefinitionMap】。
- ImportBeanDefinitionRegistrar接口是Spring的扩展点之一,Spring容器启动时会回调所有实现了ImportBeanDefinitionRegistrar接口的实现类中的registerBeanDefinitions方法,完成自定义BeanDefinition注册。
- MapperScannerRegistrar的registerBeanDefinitions方法手动将MapperScannerConfigurer类通过这种方式将自己的BeanDefinition实例注册到了容器中,为下一步Bean初始化做准备。
- MapperScannerConfigurer类实现了BeanDefinitionRegistryPostProcessor接口,该接口也是Spring的扩展点之一,Spring容器启动时会回调所有实现了BeanDefinitionRegistryPostProcessor接口的实现类中的postProcessBeanDefinitionRegistry方法,进行BeanDefinition注册的后置处理,可以修改BeanDefinition对象。
- 在MapperScannerConfigurer的postProcessBeanDefinitionRegistry方法中创建了ClassPathMapperScanner对象,该对象对@MapperScan注解中配置的包路径进行了扫描,为每个mapper接口创建对应的BeanDefinition实例,并修改所有实例中的beanClass属性值为MapperFactoryBean,autoWireMode为byType。
- 将所有mapper接口的BeanDefinition实例注册到Spring的容器中,为下一步实例化mapper接口做准备。
- MapperFactoryBean是一个很关键的类,MapperFactryBean集成了SqlSessionDaoSupport类,实现了FactoryBean接口,覆写了getObject()方法。
- FactoryBean类型的Bean,在进行Bean初始化时,会通过调用自己的getObject()方法,获取对象;而MapperFactoryBean覆写后的getObject()方法,实际执行的是getSqlSession().getMapper(this.mapperInterface),通过此方法衔接到Mybaits,以JDK动态代理的方式,创建了一个代理对象,最后将代理对象注册到了Spring容器中。
1、定义一个注解MapperScan,注解上含有mapper扫描路径,在MapperScan注解中添加Spring注解解析器
MapperScan注解:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(MapperScannerRegistrar.class) @Repeatable(MapperScans.class) public @interface MapperScan { // 省略 }
2、注解解析器会读取路径下的mapper,并对mapper类进行解析
public class ClassPathMapperScanner { @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { //获取所有符合条件的BeanDefinitionHolder对象 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
//将beanDefinitions注册至spring容器 processBeanDefinitions(beanDefinitions); return beanDefinitions; }
//处理扫描得到的BeanDefinitionHolder集合,将集合中的每一个mapper接口转换成MapperFactoryBean后,注册至spring容器 private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { GenericBeanDefinition definition; for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); //设置代理类 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); //设置bean定义为mapperFactoryBean definition.setBeanClass(this.mapperFactoryBean.getClass()); } } }
3、将Mybatis中的代理对象注册到Spring中
通过Mybatis SqlSession获取Mapper代理对象时,然后通过FactoryBean将对象注册到Spring
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> private Class<T> mapperInterface; // 具体Mapper接口类型 @Override public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); } }