Mybatis在SpringBoot中是如何被加载执行
首先依赖于springboot的自动装配@EnableAutoConfiguration注解,这个注解最终帮助我们读取mybatis-spring-boot-autoconfigure-x.x.x.jar中的META-INF\spring.factories配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
来看MybatisAutoConfiguration的源码,最主要的就是AutoConfiguredMapperScannerRegistrar。
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {//...@Configuration@Import({AutoConfiguredMapperScannerRegistrar.class})@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {public MapperScannerRegistrarNotFoundConfiguration() {}public void afterPropertiesSet() {MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");}}public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {private BeanFactory beanFactory;public AutoConfiguredMapperScannerRegistrar() {}public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {if (!AutoConfigurationPackages.has(this.beanFactory)) {MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");} else {// 这里获取要扫描的包名MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");List<String> packages = AutoConfigurationPackages.get(this.beanFactory);if (MybatisAutoConfiguration.logger.isDebugEnabled()) {packages.forEach((pkg) -> {MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);});}// 下面这些代码主要就是定义一个bean的定义,添加到BeanFactory中 BeanDefinitionBuilderBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders", true);// 这就是要扫描的注解类型,就是@Mapperbuilder.addPropertyValue("annotationClass", Mapper.class);// //这里是要扫描的包的路径builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);Set<String> propertyNames = (Set)Stream.of(beanWrapper.getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());if (propertyNames.contains("lazyInitialization")) {builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");}if (propertyNames.contains("defaultScope")) {builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");}registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());}}public void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}}
}
AutoConfiguredMapperScannerRegistrar主要就是把MapperScannerConfigurer这个类注册到spring中,来看MapperScannerConfigurer的代码:
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {//...@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {if (this.processPropertyPlaceHolders) {//这个是主要设置一些属性,比如上面包名,要扫描的注解类名称等等processPropertyPlaceHolders();}//这个类看名字都知道是干什么的, 主要就是扫描mapper注解的类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));}// ...
}
由于MapperScannerConfigurer这个类实现了BeanDefinitionRegistryPostProcessor,所以它就会被生成bean之前加载,调用它的postProcessBeanDefinitionRegistry方法,postProcessBeanDefinitionRegistry里面就会scan我们指定的package里的@Mapper类。再来看ClassPathMapperScanner:
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {//...@Overridepublic Set<BeanDefinitionHolder> doScan(String... basePackages) {Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);if (beanDefinitions.isEmpty()) {logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");} else {processBeanDefinitions(beanDefinitions);}return beanDefinitions;}private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {GenericBeanDefinition definition;for (BeanDefinitionHolder holder : beanDefinitions) {definition = (GenericBeanDefinition) holder.getBeanDefinition();if (logger.isDebugEnabled()) {logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface");}// the mapper interface is the original class of the bean// but, the actual class of the bean is MapperFactoryBean//这里是给bean定义的添加一个构造方法参数,就是我们扫描出来mapper注解类的类名definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59// 这个就是设置对应bean的类的类,这里设置成了org.mybatis.spring.mapper.MapperFactoryBean这个类,这注意这个类实现了FactoryBean接口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) {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) {logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");}definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);explicitFactoryUsed = true;}if (!explicitFactoryUsed) {if (logger.isDebugEnabled()) {logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");}definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);}}}//...
}
最终在获取bean的时候,会调用MapperFactoryBean这个类的getObject():
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {private Class<T> mapperInterface;// ...public MapperFactoryBean(Class<T> mapperInterface) {this.mapperInterface = mapperInterface;}/*** {@inheritDoc}*/@Overridepublic T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);}/*** {@inheritDoc}*/@Overridepublic Class<T> getObjectType() {return this.mapperInterface;}//....
}
getObject()里会返回代理对象,对象的类型即 构造函数里传进来的 mapperInterface 。
的加载,beanFatory加载@Mapper类
相关文章:
Mybatis在SpringBoot中是如何被加载执行
首先依赖于springboot的自动装配EnableAutoConfiguration注解,这个注解最终帮助我们读取mybatis-spring-boot-autoconfigure-x.x.x.jar中的META-INF\spring.factories配置类: org.springframework.boot.autoconfigure.EnableAutoConfiguration\ org.myb…...
数据采集用,集成了主流工业通讯协议
IoTClient 是一个物联网设备通讯协议实现客户端,集成了主流工业通讯协议,包括主流PLC通信读取、ModBus协议、Bacnet协议等。该组件基于.NET Standard 2.0,适用于.NET的跨平台开发,可在Windows、Linux等系统上运行,甚至…...
Django(三)-搭建第一个应用(2)
一、编写更多视图 问题详情页——展示某个投票的问题和不带结果的选项列表。问题结果页——展示某个投票的结果。投票处理器——用于响应用户为某个问题的特定选项投票的操作。 # 1.问题详情页:展示某个投票的问题和不带结果的选项列表 def detail(request,questi…...
求助:配置脚手架代理,跨域问题proxyTable配置无效,访问后显示404?
已经在这里卡了一天了。找了很多解决办法,比如重启,修改proxytable等等,但是每次但是404,求助各位大佬,怎么解决? 1、代码 (1)config的index.js (2) App.v…...
【4月】组队打卡《山有木Python特征工程极简入门》
活动名称 CDA Club 第2期《山有木兮Python数据分析极简入门》组队打卡 活动介绍 本次打卡活动由CDA俱乐部旗下学术部主办。目的是通过数据分析科普内容,为数据分析爱好者提供学习和交流的机会。方便大家利用碎片化时间在线学习,以组队打卡的形式提升学…...
Wireshark 抓包
启动时选择一个有信号的网卡双击打开,或者在 捕获选择里打开选择网卡。 然后输出下面的规则就可以抓到报文了。 最上面的三条是建立连接时的三次握手, 下面是发送数据hello 对应两条数据 最下面的4条是断时的4次挥手...
c语言运算符优先级
1、运算符介绍 在C语言中,运算符优先级是指在表达式中执行运算的先后顺序。按照C语言的标准规范,不同的运算符被赋予了不同的优先级等级,优先级高的运算符会先进行运算。如果同一优先级的运算符出现在同一个表达式中,则按照从左到…...
纳斯达克大屏媒体尺寸与投放费用:一次投放需要多少钱?
纳斯达克大屏媒体尺寸与投放费用:一次投放需要多少钱? 1. 纳斯达克图片要求 1.1 像素要求 高度:2336 像素宽度:1832 像素 1.2 分辨率要求 像素比率:1.0 px 72 dpi 1.3 文件格式要求 静态图片格式:.…...
将word转为PDF的几种简单方式
第一种:使用spire.doc.jar包,用时7秒左右。 引入spire.doc-11.1.1.jar包,该包带水印,建议使用免费版的spire.doc.free-5.2.0.jar,免费版只能转三页。 package web.tools.excel; import com.spire.doc.*; public cl…...
大型集团公司企业文化知识竞活动赛策划方案
一场高端企业文化知识竞赛活动完整策划书,按诗词大会舞美标准进行设计,竞赛规则新颖,值得收藏。 天纵高端知识竞赛服务商,20多年现场经验和软硬件开发。 专业承办全国高端知识竞赛活动。线上线下各类竞赛活动均可执行,…...
Spring Boot设置io临时目录
在部署springboot项目,使用MultipartFile上传文件会出现以下异常 Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [/tmp/tomcat.3016596448718765136.18001/work/Tomcat/localhost/xx] is …...
Polar 2024春季个人挑战赛 Jay17 WP
Polar 2024春季个人挑战赛 Rank:7 【WEB】机器人 开题 起手敏感文件robots.txt 【WEB】PHP反序列化初试 最简单的php反序列化 POC: <?php class Easy{public $name;public function __wakeup(){echo $this->name;} } class Evil{public $evi…...
10 mybatis 日志
文章目录 product.sqlpom.xmllogback.xmlmybatis-config.xmlProductsMapper.xmlProductsProductsMapper.java product.sql create table products (product_id int auto_increment comment 产品IDprimary key,product_name varchar(100) null comment 产品名称,bra…...
AJAX介绍使用案例
文章目录 一、AJAX概念二、AJAX快速入门1、编写AjaxServlet,并使用response输出字符(后台代码)2、创建XMLHttpRequest对象:用于和服务器交换数据 & 3、向服务器发送请求 & 4、获取服务器响应数据 三、案例-验证用户是否存…...
【echart】数据可视化
什么是数据可视化? 数据可视化主要目的:借助于图形化手段,清晰有效地传达与沟通信息。 数据可视化可以把数据从冰冷的数字转换成图形,揭示蕴含在数据中的规律和道理。 如何绘制? echarts 图表的绘制,大体分为三步:…...
排序(冒泡/快速/归并)
冒泡排序 时间复杂度为 O(n^2) 原理 比较相邻的元素. 如果第一个比第二个大,就交换他们两个.依次比较每一对相邻的元素—>结果 : 最后的元素是这组数中最大的重复上述步骤 , 除了最后一个[]因为最后一个已经是排好序的了(这组数中最大的那个)]持续对越来越少的元素进行如上…...
jq中的跨域
跨域 1.从一个地址到另外一个第一请求资源或者数据时,就有可能发生跨域 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>跨域</title><script src"jquery/jquery-1.11.3.j…...
CUDA学习笔记08: 原子规约/向量求和
参考资料 CUDA编程模型系列一(核心函数)_哔哩哔哩_bilibili 代码 #include <iostream> #include <cuda_runtime.h> #include <device_launch_parameters.h> #include <stdio.h> #include <math.h>#define N 10000000 #define BLOCK 256 #def…...
PointNet++论文复现(一)【PontNet网络模型代码详解 - 分类部分】
PontNet网络模型代码详解 - 分类部分 专栏持续更新中!关注博主查看后续部分! 分类模型的训练: ## e.g., pointnet2_ssg without normal features python train_classification.py --model pointnet2_cls_ssg --log_dir pointnet2_cls_ssg python test_classification.py…...
AI渣土车监测报警摄像机
随着城市建设的不断发展和交通运输的快速增长,渣土车作为建筑行业中不可或缺的运输工具,承担着大量的渣土运输任务。然而,由于渣土车在运输过程中存在超速、违规变道、碾压行人等交通安全问题,给道路交通和行人安全带来了严重的隐…...
别再折腾无障碍服务了!用Android蓝牙HID实现投屏反控的保姆级避坑指南
蓝牙HID协议在Android投屏反控中的深度实践 如果你正在开发一款类似Scrcpy的Android投屏工具,肯定遇到过这样的困境:无障碍服务(AccessibilityService)的授权流程繁琐且容易被厂商拦截,反射调用InputManagerService又需要系统级权限。这时候&…...
Unity Input System手势识别避坑指南:为什么你的双指缩放总是不跟手?
Unity Input System手势识别避坑指南:为什么你的双指缩放总是不跟手? 当你在Unity中实现双指缩放功能时,是否遇到过这样的问题:用户手指明明在屏幕上流畅滑动,但画面却像卡顿了一样,或者缩放比例突然跳变&a…...
电视盒变身记:3步打造你的家庭全能服务器,闲置设备重获新生!
电视盒变身记:3步打造你的家庭全能服务器,闲置设备重获新生! 【免费下载链接】amlogic-s9xxx-armbian amlogic-s9xxx-armbian: 该项目提供了为Amlogic、Rockchip和Allwinner盒子构建的Armbian系统镜像,支持多种设备,允…...
一般非线性最优问题的迭代解法思路
1.迭代方法在经典最优化极值问题中,解析法虽然具有概念简明,计算精确等优点,但因只能适用于简单或特殊问题的寻优,对于复杂的工程实际问题通常无能为力,一般采用迭代算法,逐渐逼近最优解。 最优化问题的迭…...
解决设计开发断层:Figma Code Connect的7个革新性实践
解决设计开发断层:Figma Code Connect的7个革新性实践 【免费下载链接】code-connect A tool for connecting your design system components in code with your design system in Figma 项目地址: https://gitcode.com/GitHub_Trending/co/code-connect 设计…...
python中的枚举类
一些具有特殊含义的类,其实例化对象的个数往往是固定的,比如用一个类表示月份,则该类的实例对象最多有 12 个;再比如用一个类表示季节,则该类的实例化对象最多有 4 个。 针对这种特殊的类,Python 3.4 中新…...
BoltDB vs Redis 读性能对比:实测表现与原理差异
一、前言 BoltDB(bbolt)与 Redis 都是高并发场景下常见的键值存储,但存储架构、存储介质、并发模型完全不同,导致两者在读性能、延迟、并发扩展性上呈现巨大差异。 本文从原理、延迟、并发读能力、资源开销四个维度对比两者的读性…...
别再用requests了!用Python 3.11+的httpx和BeautifulSoup4爬取豆瓣电影Top250(附完整代码)
用Python 3.11的httpx和BeautifulSoup4高效爬取豆瓣电影Top250 在Python爬虫领域,技术栈的迭代速度令人目不暇接。十年前流行的urllib2如今已被更现代、更高效的库所取代。本文将带你使用Python 3.11的最新特性,结合httpx和BeautifulSoup4这两个强力工具…...
高效流畅的WindowsB站体验:BiliBili-UWP第三方客户端全方位指南
高效流畅的WindowsB站体验:BiliBili-UWP第三方客户端全方位指南 【免费下载链接】BiliBili-UWP BiliBili的UWP客户端,当然,是第三方的了 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBili-UWP 作为一名Windows平台的B站用户&…...
从零到一:OpCore-Simplify如何让黑苹果配置变得如此简单?
从零到一:OpCore-Simplify如何让黑苹果配置变得如此简单? 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 还在为复杂的OpenCor…...
