深入源码理解Spring整合MyBatis原理 (6)

回到ClassPathMapperScanner#scan(),该方法内部会继续调用doScan()方法。

/** * Calls the parent search that will search and register all the candidates. * Then the registered objects are post processed to set them as * MapperFactoryBeans */ @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { //先调用父类ClassPathBeanDefinitionScanner#doScan()方法 //扫描并将Bean信息整合成BeanDefinition注册进Spring容器,且包装成BeanDefinitionHolder返回 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { // 重要!!! 将BeanDefinition的定义适配成MapperFactoryBean。(当前BeanDefinition的beanClass是Mapper Interface,是无法实例化的。) processBeanDefinitions(beanDefinitions); } return beanDefinitions; } 加工Mapper的BeanDefinition-适配成MapperFactoryBean

如下是processBeanDefinitions()的核心代码片段

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { GenericBeanDefinition definition; for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); // 省略代码 ...... // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean // 添加构造函数参数值,当前Mapper的Class。 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59 // 将Bean的类型定义修改为MapperFactoryBean,这样实例化出来的就是一个MapperFactoryBean了 definition.setBeanClass(this.mapperFactoryBean.getClass()); definition.getPropertyValues().add("addToConfig", this.addToConfig); // 省略代码 ...... } }

这段代码非常关键!首先,它对Bean的构造函数参数值做了干预,将当前的BeanClassName设置进去了(如UserMapper.class),而从第二行代码中也能知道该Bean的Class被修改成了MapperFactoryBean,所以我们去看看MapperFactoryBean的构造函数就行了。

public MapperFactoryBean(Class<T> mapperInterface) { // Mapper Interface。(如UserMapper.class) this.mapperInterface = mapperInterface; } /** * {@inheritDoc} */ @Override public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); // 等同于如:sqlSession.getMapper(UserMapper.class) }

其次它将Bean的实例化类型从无法实例化的Mapper Interface修改成了可以实例化的MapperFactoryBean类型。

以上操作后,就将一个Mapper Bean包装成了MapperFactoryBean,而交给Spring管理的是Mapper对应的代理实例(通过mapperInterface字段绑定关系),所以我们就能通过@Autowired将Mapper(MapperFactoryBean#getObject())依赖注入进来直接使用了。

到此,Spring整合MyBatis的内容就结束了。

Spring事务管理器-SpringManagedTransaction

再顺便聊一下其中的变动-事务管理器,因为Spring整合了MyBatis所以后续的事务就应该由Spring来管理了。

之前在MyBatis中如果配置的是“JDBC",则是JdbcTransactionFactory

深入源码理解Spring整合MyBatis原理

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzsjsw.html