转载至:https://www.cnblogs.com/jpfss/p/7799806.htmlhtml
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Springjava
Mybatis在与Spring集成的时候能够配置MapperFactoryBean来生成Mapper接口的代理. 例如spring
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
MapperFactoryBean 建立的代理类实现了 UserMapper 接口,而且注入到应用程序中。 由于代理建立在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而 不是一个具体的实现类。sql
上面的配置有一个很大的缺点,就是系统有不少的配置文件时 所有须要手动编写,因此上述的方式已经很用了。mybatis
没有必要在 Spring 的 XML 配置文件中注册全部的映射器。相反,你可使用一个 MapperScannerConfigurer , 它 将 会 查 找 类 路 径 下 的 映 射 器 并 自 动 将 它 们 创 建 成 MapperFactoryBean。app
要建立 MapperScannerConfigurer,能够在 Spring 的配置中添加以下代码:ide
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="org.mybatis.spring.sample.mapper" /> </bean>
basePackage 属性是让你为映射器接口文件设置基本的包路径。 你可使用分号或逗号 做为分隔符设置多于一个的包路径。每一个映射器将会在指定的包路径中递归地被搜索到。post
注 意 , 没 有 必 要 去 指 定 SqlSessionFactory 或 SqlSessionTemplate , 因 为 MapperScannerConfigurer 将会建立 MapperFactoryBean,以后自动装配。可是,若是你使 用了一个 以上的 DataSource ,那 么自动 装配可 能会失效 。这种 状况下 ,你可 以使用 sqlSessionFactoryBeanName 或 sqlSessionTemplateBeanName 属性来设置正确的 bean 名 称来使用。这就是它如何来配置的,注意 bean 的名称是必须的,而不是 bean 的引用,因 此,value 属性在这里替代一般的 ref:this
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
MapperScannerConfigurer 支 持 过 滤 由 指 定 的 创 建 接 口 或 注 解 创 建 映 射 器 。 annotationClass 属性指定了要寻找的注解名称。 markerInterface 属性指定了要寻找的父 接口。若是二者都被指定了,加入到接口中的映射器会匹配两种标准。默认状况下,这两个 属性都是 null,因此在基包中给定的全部接口能够做为映射器加载。spa
被发现的映射器将会使用 Spring 对自动侦测组件(参考 Spring 手册的 3.14.4)默认的命 名策略来命名。也就是说,若是没有发现注解,它就会使用映射器的非大写的非彻底限定类 名。可是若是发现了@Component 或 JSR-330 的@Named 注解,它会获取名称。注意你能够 配 置 到 org.springframework.stereotype.Component , javax.inject.Named(若是你使用 JSE 6 的话)或你本身的注解(确定是自我注解)中,这 样注解将会用做生成器和名称提供器。
接下来让咱们看一下MapperScannerConfigurer类的源码 看看是如何自动扫描的。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { this.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, ",; \t\n")); }
把Mapper接口转换成MapperFactoryBean的代码在地17行这个方法里,让咱们跟踪进去看一下。
org.mybatis.spring.mapper.ClassPathMapperScanner
public Set<BeanDefinitionHolder> doScan(String... basePackages) { Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { this.processBeanDefinitions(beanDefinitions); } return beanDefinitions; } private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { Iterator var3 = beanDefinitions.iterator(); while(var3.hasNext()) { BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next(); GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition(); if (this.logger.isDebugEnabled()) { this.logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface"); } definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); //将mapper的接口,转化成mapperFactoryBean注入到spring的IOC容器 definition.setBeanClass(this.mapperFactoryBean.getClass()); definition.getPropertyValues().add("addToConfig", this.addToConfig); boolean explicitFactoryUsed = false; if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) { definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionFactory != null) { definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory); explicitFactoryUsed = true; } if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { if (explicitFactoryUsed) { this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionTemplate != null) { if (explicitFactoryUsed) { this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); explicitFactoryUsed = true; } if (!explicitFactoryUsed) { if (this.logger.isDebugEnabled()) { this.logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); } definition.setAutowireMode(2); } } }