Mybatis如何集成到Spring中的
所谓集成其实说白了就是将mybatis的组件注入到spring容器中,让spring去管理这些组件。下面这段配置我们集成mybatis的时候经常用到:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据源 -->
<property name="dataSource" ><ref bean="dataSource" /></property>
<!-- 别名 -->
<property name="typeAliasesPackage" value="com.nickyu.learn.mybatis.entity"></property>
<!-- sql映射文件路径 -->
<property name="mapperLocations" value="classpath*:com/nickyu/learn/mybatis/mapper/xml/*.xml"></property>
</bean>
<!--4 自动扫描对象关系映射 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
sqlSessionFactory的作用就是产生一个SqlSessionFactory,而真正将我们写的Mapper接口注入到容器中的就是MapperScannerConfigurer起到的作用,它会根据配置信息(比如配置扫描的包名,注解啥的)扫描所有的Mapper接口,它的实现原理是:
MapperScannerConfigurer本身是一个BeanDefinitionRegistryPostProcessor后置处理器,应用容器在刷新的时候会回调它的postProcessBeanDefinitionRegistry方法:
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();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
从方法体中可以看出,mybatis自定义了一个扫描器ClassPathMapperScanner,这个扫描器主要做了两件事,1、扫描所有的Mapper接口并转换为BeanDefinition 2、对BeanDefinition做修改,比如将它的beanClass改为MapperFactoryBean,设置sqlSessionFactory属性等待。
阅读Mybatis源码可以发现,我们自定义的Mapper接口为什么能在程序中正常使用,是因为Mybatis使用了JDK动态代理技术生成了一个代理对象:
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
也就是说spring容器中管理的其实是这些代理对象。