Mybatis MapperScannerConfigurer自动扫描Mapper接口生成代理注入到Spring的方法

前言

Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置 MapperFactoryBean来生成Mapper接口的代理。

例如:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
 <property name="mapperInterface" value="com.bijian.study.dao" />
 <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

MapperFactoryBean创建的代理类实现了 UserMapper 接口,并且注入到应用程序中。 因为代理创建在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而 不是一个具体的实现类。

上面的配置有一个很大的缺点,就是系统有很多的配置文件时 全部需要手动编写,所以上述的方式已经很用了。

没有必要在 Spring 的 XML 配置文件中注册所有的映射器。相反,你可以使用一个 MapperScannerConfigurer,它 将 会 查 找 类 路 径 下 的 映 射 器 并 自 动 将 它 们 创 建 成 MapperFactoryBean。

要创建 MapperScannerConfigurer,可以在 Spring 的配置中添加如下代码:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
 <property name="mapperInterface" value="com.bijian.study.dao" />
 <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

basePackage 属性是让你为映射器接口文件设置基本的包路径。 你可以使用分号或逗号 作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到。

注意,没 有 必 要 去 指 定 SqlSessionFactory 或 SqlSessionTemplate , 因 为 MapperScannerConfigurer 将会创建 MapperFactoryBean,之后自动装配。但是,如果你使 用了一个 以上的 DataSource ,那 么自动 装配可 能会失效 。这种 情况下 ,你可 以使用 sqlSessionFactoryBeanName 或 sqlSessionTemplateBeanName 属性来设置正确的 bean 名 称来使用。这就是它如何来配置的,注意 bean 的名称是必须的,而不是 bean 的引用,因 此,value 属性在这里替代通常的ref。

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

整体配置如下所示:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="mapperLocations" value="classpath*:**/*Dao*.xml"></property>
</bean>
<!-- dao配置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="com.bijian.study.dao" />
	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>

MapperScannerConfigurer 支 持 过 滤 由 指 定 的 创 建 接 口 或 注 解 创 建 映 射 器 。 annotationClass 属性指定了要寻找的注解名称。 markerInterface 属性指定了要寻找的父 接口。如果两者都被指定了,加入到接口中的映射器会匹配两种标准。默认情况下,这两个 属性都是 null,所以在基包中给定的所有接口可以作为映射器加载。

被发现的映射器将会使用 Spring 对自动侦测组件(参考 Spring 手册的 3.14.4)默认的命 名策略来命名。也就是说,如果没有发现注解,它就会使用映射器的非大写的非完全限定类 名。但是如果发现了@Component 或 JSR-330 的@Named 注解,它会获取名称。注意你可以 配 置 到 org.springframework.stereotype.Component , javax.inject.Named(如果你使用 JSE 6 的话)或你自己的注解(肯定是自我注解)中,这 样注解将会用作生成器和名称提供器。

接下来让我们看一下MapperScannerConfigurer类的源码 看看是如何自动扫描的。

/** 
 * {@inheritDoc} 
 * 
 * @since 1.0.2 
 */ 
@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)); 
} 
把Mapper接口转换成MapperFactoryBean的代码在scanner.scan方法里,让我们跟踪进去看一下。

/** 
 * Perform a scan within the specified base packages. 
 * @param basePackages the packages to check for annotated classes 
 * @return number of beans registered 
 */ 
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); 
} 
/** 
 * Perform a scan within the specified base packages, 
 * returning the registered bean definitions. 
 * <p>This method does <i>not</i> register an annotation config processor 
 * but rather leaves this up to the caller. 
 * @param basePackages the packages to check for annotated classes 
 * @return set of beans registered if any for tooling registration purposes (never {@code null}) 
 */ 
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { 
 Assert.notEmpty(basePackages, "At least one base package must be specified"); 
 Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(); 
 for (String basePackage : basePackages) { 
 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 
 for (BeanDefinition candidate : candidates) { 
  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); 
  candidate.setScope(scopeMetadata.getScopeName()); 
  String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); 
  if (candidate instanceof AbstractBeanDefinition) { 
  postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); 
  } 
  if (candidate instanceof AnnotatedBeanDefinition) { 
  AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); 
  } 
  if (checkCandidate(beanName, candidate)) { 
  BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); 
  definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); 
  beanDefinitions.add(definitionHolder); 
  registerBeanDefinition(definitionHolder, this.registry); 
  } 
 } 
 } 
 return beanDefinitions; 
} 

热门文章

暂无图片
编程学习 ·

自举功能 - 软件复位

说明对于需要长时间运行的电子产品,例如:安防监控等,如果设备程序崩溃后不能自动恢复,可能会出现以下情况:设备操作无反应,用户以为设备坏掉了,并不知道需要断电重启,对产品质量怀疑。 程序崩溃后所有功能中断,有些重要并且需要长时间稳定运行的功能无法延续,例如:定…
暂无图片
编程学习 ·

Python学习:变量

Python 变量类型 变量存储在内存中的值。这就意味着在创建变量时会在内存中开辟一个空间。 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中。 因此,变量可以指定不同的数据类型,这些变量可以存储整数,小数或字符。变量赋值 Python 中的变量赋…
暂无图片
编程学习 ·

数据重删和数据压缩主流技术分析

数据压缩随着计算能力的不断提升,当代社会正在产生越来越巨量的数据,数据压缩也被应用在生活的方方面面,如在网上打开的图片、视频、音频等都是经过压缩的。压缩可以分为无损压缩和有损压缩。无损压缩可以通过压缩文件完全恢复原始文件;而有损压缩则会丢失一部分信息。对于…
暂无图片
编程学习 ·

Day 11 武装飞船

《外星人入侵》游戏要实现的是:玩家控制一艘出现在屏幕底部中央的飞船,可以使用箭头左右移动飞船,还可以使用空格来进行射击,游戏开始时候一群外星人出现在天空,他们在屏幕中向下移动,玩家的任务是射杀这些外星人,玩家将所有外星人都消灭干净后,会出现一群新的外星人,…
暂无图片
编程学习 ·

Spring boot的项目文件

1.src–>main–>java 是用来放Java文件2.resources是用来放配置文件 application.properties用来放配置文件的信息3.test用来放一些测试用例4.新建一个Java类5.解决@RequestMapping报Cannot resolve symbol RestController’错误 解决办法: 在错误处按alt+enter 选择a…
暂无图片
编程学习 ·

大数据分析的作用有哪些

大数据分析的出现不但可以让老百姓的生活更加便捷,同时也可以提高企业的竞争力,无论是哪个行业以及具体的企业都会有与之对应的大数据分析,而今天就来说说大数据分析对于企业有哪些帮助。数据分析目的1:分类检查未知分类或暂时未知分类的数据,目的是预测数据属于哪个类别或…
暂无图片
编程学习 ·

去掉无用节点

using UnityEngine; using UnityEditor; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using UnityEditorInternal;// 美术在导出模型时,有很多挂点是没有用的。但有些挂点却是有用的,跟美术沟通,有用挂点的名字。// 再使用…
暂无图片
编程学习 ·

直播软件开发中的音视频编码转换怎么实现

2.1、下载ffmpeg。 下载网址:[url]http://www.ffmpeg.org/download.html[/url] 2.2、解压缩tar -zxvf ffmpeg-2.0.1.tar.gz2.3、编辑profile文件: vi /etc/profile 在文件末尾加上两句话:export FFMPEG_HOME=/usr/local/ffmpeg export PATH=$FFMPEG_HOME/bin:$PATH2.4、配置…
暂无图片
编程学习 ·

vue+ts报错 Parsing error: Unexpected token

1.检查是否安装 babel-eslint2.打开.eslint.js文件检查部分属性和下方的是否匹配// ESlint 检查配置 module.exports = {root: true,parserOptions: {parser: babel-eslint,sourceType: module},parser: "vue-eslint-parser",//------------env: {browser: true,node…
暂无图片
编程学习 ·

Spring测试中的事务

目录 文章目录@Transactional @Transactional 1、测试方法加上该注解后事务自动回滚。 2、@BeforeEach与@AfterEach在测试方法的事务中执行 3、@BeforeTransactional与@AfterTransactional在事务执行之前之后执行;并且没有加@Transactional的测试方法不执行这两个注解下的方法…
暂无图片
编程学习 ·

ssm框架下简单的增删改查实现

ssm框架下简单的增删改查实现 代码太多就不逐一展示了,到目前为止这几个类之间的关系还是有点不太清楚。 package controller;import bean.User; import dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype…
暂无图片
编程学习 ·

迭代器

概念 提供对对象的间接访问,有效的迭代器或者指向某个元素,或者指向容器中尾元素的下一位置 使用 获取 begin()返回指向第一个元素/字符的迭代器 end()返回指向容器(或string)尾元素的下一位置即根本不存在的尾后元素解引用 如it为vector对象的迭代器:(*it).empty()或者it-&…
暂无图片
编程学习 ·

Linux学习日记 7.1 (用户)

MOOC链接 一。什么是用户和用户组 1.用户 UID (User‘s ID)是识别用户权限的标识,用户登陆系统所处的角色是通过UID来实现的,而非用户名,因此,每个用户的UID必须是唯一的。 Linux中的用户分成三类 ※ 系统管理员用户:拥有整个系统所有的权限,只能有一个,即根用户root,…
暂无图片
编程学习 ·

计算机基础————存储单位and数制位

存储单位 最小存储单位:bit 存储0或者1的空间 基本存储单位:byte 1Byte=8bit 1KB=2^10Byte=1024Byte 1MB=210KB=1024KB GB=1024MB TB=1024GB 数制位 二进制:每一位由0-1组成,满2进1 权为2 101011110 十进制:每一位0-9组成,满10进1 权为10 95 八进制:每一位…
暂无图片
编程学习 ·

HashMap的高效遍历方式

HashMap<Integer,Integer> map = new HashMap<>(); 第一种(直接keySet()或者values()遍历): for(Integer key:map.keySet()){System.out.println("key:"+key+",value:"+map.get(key)); }第二种(使用entrySet,底层也使用的迭代器,高效):…
暂无图片
编程学习 ·

11.1 函数的默认参数

11.1 函数的默认参数 之前我们学过的,如果函数由形参,那么调用函数时要传递对性的实参。 事实上,函数可以有默认参数,这样如果不传递实参,则按照默认值给形参传值。函数声明和实现只能有一个默认参数,不能重复定义默认参数。 如果某个形参有了默认参数,则位于这个形参之…
暂无图片
编程学习 ·

Jmeter之JDBC的使用

(一)环境准备 1、下载mysql-connector-java-x.x.x.jar放到 jmeter根目录的lib目录下,重启jmeter(二)数据库配置 1、在测试计划下面,添加一个setup线程组2、在setup线程组下,添加一个配置元件JDBC Connection Configuration3、填写配置信息 Variable Name:数据库连接池的…
暂无图片
编程学习 ·

算法与数据结构(part3)--数据结构

学习笔记,仅供参考,有错必纠文章目录算法与数据结构--基于python数据结构什么是数据结构数据结构的概念抽象数据类型(ADT)算法与数据结构–基于python数据结构什么是数据结构我们为了解决问题,需要将数据保存下来,然后根据数据的存储方式来设计算法,数据的存储方式不同,会…