在上面demo中,我们定义了一个dao接口,并没有实现类,然后直接调用接口的方法,就可以执行mapper里的sql。这是怎么做到的呢。
在这篇文章中,我们分析到:mapper.xml对应的dao类会添加到configuration的MapperRegistry的Map<Class<?>, MapperProxyFactory<?>> knownMappers里,key是类的全名,value是对应的代理对象。
入口就在这里,在xml配置文件中,我们会有以下配置,启动扫描配置路径下的dao类
<!-- 自动扫描了所有的XxxxMapper.xml对应的mapper接口文件,这样就不用一个一个手动配置Mpper的映射了,只要Mapper接口类和Mapper映射文件对应起来就可以了。 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.rice.mvc.dao" />
</bean>
我们来看看MapperScannerConfigurer类,它实现了BeanDefinitionRegistryPostProcessor,我们找到对应的postProcessBeanDefinitionRegistry方法,如下
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
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));
}
processPropertyPlaceHolders();方法是做配置解析的。重点在ClassPathMapperScanner.scan方法。ClassPathMapperScanner继承于ClassPathBeanDefinitionScanner。来看scan方法,这是ClassPathBeanDefinitionScanner.scan,如下
public int scan(String... basePackages) {
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
再看doScan,这里调用的是ClassPathMapperScanner.doScan,如下
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (