Spring源码分析总结——Mybatis的整合

该文章基于《Spring源码深度解析》撰写,感谢郝佳老师的奉献

Mybatis与Spring整合

和之前分析的步骤相同,我们先从工厂方法开始分析,对于Mybatis整合的工厂类就是org.mybatis.Spring.SqlSessionFactoryBean
《Spring源码分析总结——Mybatis的整合》
其中有两个值得一提的接口,就是
InitializingBean接口:实现此接口的bean会在初始化时调用器afterPropertiesSet方法来进行bean的逻辑初始化,并通过configuration实例来承载每一步所获取的信息,为创建SqlSessionFactory实例作准备。
FactoryBean接口:将getBean方法转换为getObject方法,所以实际上得到的是通过onfiguration属性和getObject方法返回的初始化后的sqlSessionFactory属性

接下来时另一个配置bean MapperFactoryBean
我们通过区分两种获取XXMapper的方式可以看出一些区别:
1.单独使用Mybatis时:
XXMapper xxmapper = sqlsession.getMapper(XXMapper.class);
2.Spring整合之后
XXMapper xxmapper = (XXMapper)context.getBean(“XXMapperID”);
《Spring源码分析总结——Mybatis的整合》
Mapper的类继承关系如上图所示,可以看到它和SqlSessionFactoryBean一样实现了InitializingBean接口和FactoryBean接口,这两个接口的功能就不再赘述。
InitializingBean接口
需要注意的是InitializingBean接口的afterPropertiesSet()是由DaoSupport类实现的,在该父类的方法中实现了以下几个功能:
1.父类对于sqlSesion不为空的验证,sqlSession作为根据接口创建映射器代理的接触类一定不可以为空,而sqlSession又是在设定sqlSessionFactory属性时完成的,所以实际上将会检测:
<bean id=… class=”org.mybatis.Spring.mapper.MapperFactoryBean”>
<property name=”sqlSessionFactory” ref=..>该属性是否存在
<bean>
2.映射接口的验证(sqlSession会根据接口动态的创建相应代理类,所以接口必不可少)
3.映射文件存在性验证
FactoryBean接口
源代码

public T getObject() throws Exception {
            return this.getSqlSession().getMapper(this.mapperInterface);
}

很简单,就是将已经注册的MapperInterface返回

如果我们需要指定搜索的包路径我们需要在applicationContext.xml中添加额外的配置

<bean class="org.mybatis.Spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="指定的搜索路径">
</bean>

这时我们又会引入新的类MapperScannerConfigurer,看一下这个类的类层次结构:
《Spring源码分析总结——Mybatis的整合》
其中出现了我们一直提到的接口InitializingBean接口,但是结果并没有那么顺利,这个接口的作用只是对一堆属性的验证代码。
但是我们还有一个经常出现的接口BeanFactoryPostProcessor及其子类BeanDefinitionRegistryPostProcessor接口,这两个接口都会在Spring初始化的过程中进行调用。
首先看BeanFactoryPostProcessor接口的postProcessBeanFactory方法

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

这是一个空实现,看看BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            this.processPropertyPlaceHolders();//1
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        scanner.registerFilters();//2
      scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));//3
 }

我们首先关注this.processPropertyPlaceHolders()这个部分,这个函数有一个很重要的说明,就是BeanDefinitionRegistris方法会在应用启动时就开始调用,并且会早于BeanFactoryPostProcessors调用,这就意味着PropertyResourceConfigurers并未被加载,所以所有对属性文件的引用都会失效。所以我们需要在MapperScannerConfigurer的配置文件中显式的配置processPropertyPlaceHolders如下配置所示:

<bean class = "org.mybatis.Spring.mapper.MapperScannerConfigurer> <property ...> <property name="processPropertyPlaceHolders" value="true"> //通过显示得配置引导程序进入processPropertyPlaceHolders方法 //从而显示地读取属性文件 </bean>

接下来我们关注2号注解scanner.registerFilters();//2这个方法主要是根据前一段代码的属性配置生成对应的过滤器,主要处理了:
1.annotationClass属性(根据设置的annotationClass生成能够达到用户效果的过滤器)
2.markerInterface属性(目的同上)
3.全局默认处理(随上面两者的值进行改变,如果都未设定将生成默认过滤器接受所有接口文件)
4.package-info.java处理(排出package-info命名的Java文件)

最后就是注释3scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, “,; \t\n”));//3收尾的工作了,这个方法主要完成了下面的步骤:
1.首先根据传入的包信息生成绝对路径,并且生成相应的bean
2.根据前面第二步注册的过滤器来控制扫描的结果
3.根据不同类型的bean进行不同的操作

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/weixin_40134367/article/details/79513300
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞