Mybatis集成篇(一)

Spring 框架集成Mybatis

目前主流Spring框架体系中,可以集成很多第三方框架,方便开发者利用Spring框架机制使用第三方框架的功能。就例如本篇Spring集成Mybatis

简单集成案例:

Config配置:

@Configuration
@MapperScan(basePackages = {"com.czy.mapper"})
public class MybatisConfig {@Beanpublic SqlSessionFactory getSqlSessionFactory() throws Exception {org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();// 可以配置Mybatis相关配置configuration.setLogImpl(StdOutImpl.class);SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource());factoryBean.setConfiguration(configuration);return factoryBean.getObject();}private DataSource dataSource() {MysqlDataSource dataSource = new MysqlDataSource();dataSource.setUrl("jdbc:mysql://xxxx:3306/mybatis?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true");dataSource.setPassword("xxx");dataSource.setUser("xxx");return dataSource;}
}

Mapper文件:

public interface UserMapper {@Select("SELECT * FROM user WHERE id = #{id}")List<User> selectUser(int id);
}

主函数:

public class Main {public static void main(String[] args) throws Exception {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MybatisConfig.class);UserMapper userMapper = applicationContext.getBean(UserMapper.class);List<User> users = userMapper.selectUser(1);users.forEach(System.out::println);}
}

上面的案例是通过注解的方式进行Mybatis相关信息配置和相关Mapper使用。

原理解析

@MapperScan

在上面案例的配置文件中有个@MapperScan注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};Class<?>[] basePackageClasses() default {};Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;Class<? extends Annotation> annotationClass() default Annotation.class;Class<?> markerInterface() default Class.class;String sqlSessionTemplateRef() default "";String sqlSessionFactoryRef() default "";Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;String lazyInitialization() default "";String defaultScope() default "";boolean processPropertyPlaceHolders() default true;Filter[] excludeFilters() default {};
}

该注解中有个很重要的@Import注解;@Import是Spring框架中的一个重要特性,主要用于导入配置类或普通类,实现配置的模块化和动态配置的加载。通过使用@Import注解,可以将多个配置类组合在一起,便于管理和维护大型应用程序的配置。

也就是说MapperScan的相关处理是由MapperScannerRegistrar这个类进行逻辑处理

MapperScannerRegistrar 核心代码

@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {var mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));if (mapperScanAttrs != null) {registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,generateBaseBeanName(importingClassMetadata, 0));}}void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,BeanDefinitionRegistry registry, String beanName) {// MapperScannerRegistrar相关核心处理是由MapperScannerConfigurer处理var builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders", annoAttrs.getBoolean("processPropertyPlaceHolders"));Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");if (!Annotation.class.equals(annotationClass)) {builder.addPropertyValue("annotationClass", annotationClass);}Class<?> markerInterface = annoAttrs.getClass("markerInterface");if (!Class.class.equals(markerInterface)) {builder.addPropertyValue("markerInterface", markerInterface);}Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");if (!BeanNameGenerator.class.equals(generatorClass)) {builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));}Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);}var sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");if (StringUtils.hasText(sqlSessionTemplateRef)) {builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));}var sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");if (StringUtils.hasText(sqlSessionFactoryRef)) {builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));}List<String> basePackages = new ArrayList<>(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));if (basePackages.isEmpty()) {basePackages.add(getDefaultBasePackage(annoMeta));}var excludeFilterArray = annoAttrs.getAnnotationArray("excludeFilters");if (excludeFilterArray.length > 0) {List<TypeFilter> typeFilters = new ArrayList<>();List<Map<String, String>> rawTypeFilters = new ArrayList<>();for (AnnotationAttributes excludeFilters : excludeFilterArray) {if (excludeFilters.getStringArray("pattern").length > 0) {// in oder to apply placeholder resolverrawTypeFilters.addAll(parseFiltersHasPatterns(excludeFilters));} else {typeFilters.addAll(typeFiltersFor(excludeFilters));}}builder.addPropertyValue("excludeFilters", typeFilters);builder.addPropertyValue("rawExcludeFilters", rawTypeFilters);}var lazyInitialization = annoAttrs.getString("lazyInitialization");if (StringUtils.hasText(lazyInitialization)) {builder.addPropertyValue("lazyInitialization", lazyInitialization);}var defaultScope = annoAttrs.getString("defaultScope");if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {builder.addPropertyValue("defaultScope", defaultScope);}builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));// for spring-nativebuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(beanName, builder.getBeanDefinition());}

MapperScannerConfigurer

核心方法

@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {if (this.processPropertyPlaceHolders) {processPropertyPlaceHolders();}// MapperScannerConfigurer后置处理则由ClassPathMapperScanner进行处理var scanner = new ClassPathMapperScanner(registry, getEnvironment());scanner.setAddToConfig(this.addToConfig);scanner.setAnnotationClass(this.annotationClass);scanner.setMarkerInterface(this.markerInterface);scanner.setExcludeFilters(this.excludeFilters = mergeExcludeFilters());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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);if (StringUtils.hasText(lazyInitialization)) {scanner.setLazyInitialization(Boolean.parseBoolean(lazyInitialization));}if (StringUtils.hasText(defaultScope)) {scanner.setDefaultScope(defaultScope);}scanner.registerFilters();// 扫描basePackage相关的类型注入到Spring中scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));}

ClassPathMapperScanner

核心方法

public int scan(String... basePackages) {int beanCountAtScanStart = this.registry.getBeanDefinitionCount();this.doScan(basePackages);if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;}@Overridepublic Set<BeanDefinitionHolder> doScan(String... basePackages) {var beanDefinitions = super.doScan(basePackages);if (beanDefinitions.isEmpty()) {if (printWarnLogIfNotFoundMappers) {LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)+ "' package. Please check your configuration.");}} else {// 处理Spring BeanDefinitionprocessBeanDefinitions(beanDefinitions);}return beanDefinitions;}/***
** 这个方法主要是给Bean的属性赋能,会生成一个definition.setBeanClass(this.mapperFactoryBeanClass);
而private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;
则得出一个结论:definition生成的Bean应该是MapperFactoryBean类
**
**/
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {AbstractBeanDefinition definition;var registry = getRegistry();for (BeanDefinitionHolder holder : beanDefinitions) {definition = (AbstractBeanDefinition) holder.getBeanDefinition();var scopedProxy = false;if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {definition = (AbstractBeanDefinition) Optional.ofNullable(((RootBeanDefinition) definition).getDecoratedDefinition()).map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException("The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]"));scopedProxy = true;}var beanClassName = definition.getBeanClassName();LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName+ "' mapperInterface");// the mapper interface is the original class of the bean// but, the actual class of the bean is MapperFactoryBeandefinition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59try {Class<?> beanClass = Resources.classForName(beanClassName);// Attribute for MockitoPostProcessor// https://github.com/mybatis/spring-boot-starter/issues/475definition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, beanClass);// for spring-nativedefinition.getPropertyValues().add("mapperInterface", beanClass);} catch (ClassNotFoundException ignore) {// ignore}//private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class;// 定义了Bean的类型是MapperFactoryBean,也就相当xml配置class部分//<bean id="xxx" class="org.mybatis.spring.mapper.MapperFactoryBean">definition.setBeanClass(this.mapperFactoryBeanClass);// 设置MapperFactoryBean的相关属性definition.getPropertyValues().add("addToConfig", this.addToConfig);var explicitFactoryUsed = false;// 设置sqlSessionFactory属性值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;}// 设置sqlSessionTemplate属性值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) {LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);}definition.setLazyInit(lazyInitialization);if (scopedProxy) {continue;}if (ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope()) && defaultScope != null) {definition.setScope(defaultScope);}// 后续交由spring框架把bean注入spring上下文中if (!definition.isSingleton()) {var proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {registry.removeBeanDefinition(proxyHolder.getBeanName());}registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());}}}

从上面分析可以得到一个核心类MapperFactoryBean

MapperFactoryBean

核心方法

  @Overrideprotected void checkDaoConfig() {super.checkDaoConfig();notNull(this.mapperInterface, "Property 'mapperInterface' is required");var configuration = getSqlSession().getConfiguration();if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {try {// 在这里是我们属性的代码,Mybatis增加了mapperconfiguration.addMapper(this.mapperInterface);} catch (Exception e) {logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);throw new IllegalArgumentException(e);} finally {ErrorContext.instance().reset();}}}

有些人可能会很好奇为啥程序调用checkDaoConfig这个方法?
那我们先看这个类继承示意图:
在这里插入图片描述
一层一层父类找你会发现
DaoSupport类的afterPropertiesSet调用

public abstract class DaoSupport implements InitializingBean {protected final Log logger = LogFactory.getLog(this.getClass());public DaoSupport() {}public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {this.checkDaoConfig();try {this.initDao();} catch (Exception var2) {throw new BeanInitializationException("Initialization of DAO failed", var2);}}protected abstract void checkDaoConfig() throws IllegalArgumentException;protected void initDao() throws Exception {}
}

到这里本篇就完结了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

路面交通工具和个数识别,支持YOLO,COCO,VOC三种格式,带标注可识别自行车,摩的,公共汽车,装载机,面包车,卡车,轿车等

预处理 自动定向&#xff1a; 已应用 调整大小&#xff1a; 拉伸至 640x640 增强 每个训练示例的输出&#xff1a; 3 翻转&#xff1a; 水平 自行车 公交车

Java 线程中的分时模型和抢占模型

Java 线程中的分时模型和抢占模型 线程的调度机制决定了多个线程在 CPU 上的执行方式&#xff0c;其中主要有两种常见的模型&#xff1a;分时模型和抢占模型。这两种模型的核心区别在于线程的执行时间分配和切换方式。 1. 分时模型&#xff08;Time-Sharing Model&#xff09;…

长时间无事可做是个危险信号

小马加入的是技术开发部&#xff0c;专注于Java开发。团队里有一位姓隋的女同事&#xff0c;是唯一的web前端工程师&#xff0c;负责页面开发工作&#xff0c;比小马早两个月入职。公司的项目多以定制化OA系统为主&#xff0c;后端任务繁重&#xff0c;前端工作相对较少。在这样…

ffmpeg 预设的值 加速

centos 安装ffmpeg 编译安装 官网获取最新的linux ffmpeg 代码 https://ffmpeg.org//releases/ mkdir -p /data/app/ffmpeg cd /data/app/ffmpeg wget http://www.ffmpeg.org/releases/ffmpeg-7.1.tar.gz tar -zxvf ffmpeg-7.1.tar.gz#安装所需的编译环境 yum install -y \…

在Java中使用Apache POI导入导出Excel(二)

本文将继续介绍POI的使用&#xff0c;上接在Java中使用Apache POI导入导出Excel&#xff08;一&#xff09; 使用Apache POI组件操作Excel&#xff08;二&#xff09; 14、读取和重写工作簿 try (InputStream inp new FileInputStream("workbook.xls")) { //Inpu…

LABVIEW Modbus 串口

VISA写入&#xff1a; 写入缓冲区改为“十六进制显示”&#xff0c;并输入数据。 数据缓冲区显示&#xff1a;使用“十六进制”显示。

第四节:jsp内的request和response对象

Jsp内置对象 Requset,当客户端请求一个jsp页面的时候&#xff0c;jsp页面所在的服务器端将客户端发出的所有请求信息封装在内置对象request中&#xff0c;因此用该对象可以获得客户端提交的信息 方法&#xff1a; Void setAttribute(String key,Object obj)设置属性的属性值…

Verilog使用liberty文件中cell单元的demo

Liberty&#xff08;.lib&#xff09;文件是用来描述标准单元库中逻辑单元&#xff08;如门电路、触发器等&#xff09;的时序和功耗特性的&#xff0c;不是用来直接定义Verilog中的元件。在Verilog设计中&#xff0c;我们通常通过实例化模块&#xff08;module&#xff09;来创…

【软考速通笔记】系统架构设计师⑧——系统质量属性与架构评估

文章目录 一、前言二、软件系统质量属性2.1 开发期质量属性2.2 运行期质量属性 三、质量属性场景描述四、系统架构评估方法4.1 方法分类4.2 软件架构分析方法4.3 架构权衡分析法4.4 成本效益分析法 一、前言 笔记目录大纲请查阅&#xff1a;【软考速通笔记】系统架构设计师——…

如何寻找适合的HTTP代理IP资源?

一、怎么找代理IP资源&#xff1f; 在选择代理IP资源的时候&#xff0c;很多小伙伴往往将可用率作为首要的参考指标。事实上&#xff0c;市面上的住宅IP或拨号VPS代理IP资源&#xff0c;其可用率普遍在95%以上&#xff0c;因此IP可用率并不是唯一的评判标准 其实更应该关注的…

FCBP 认证考试要点摘要

理论知识 数据处理与分析&#xff1a;包括数据的收集、清洗、转换、存储等基础操作&#xff0c;以及数据分析方法&#xff0c;如描述性统计分析、相关性分析、数据挖掘算法等的理解和应用 。数据可视化&#xff1a;涉及图表类型的选择与应用&#xff0c;如柱状图、折线图、饼图…

初识C++:指针与引用的异同,inline关键字

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 一.指针和引用的关系 1.1 概念 1.2 相似点 1.3 不同点 二.inline关键字 2.1 概念 2.2 工作原理 2.3 使用场景 2.4 注意事项 三.nullptr 3.1 引入背景 3.2 语义和类型 3.3 使用场景 兄弟们共勉 &#xff01;&…

【软考速通笔记】系统架构设计师⑤——软件工程基础知识

文章目录 一、前言二、基础知识点2.1 软件危机2.2 软件生命周期 三、软件过程模型&#xff08;论文&#xff09;3.1 瀑布模型3.2 原型模型3.3 螺旋模型3.4 敏捷模型3.5 软件统一过程模型3.6 软件成熟度模型3.7 软件成熟度模型集成 四、需求工程五、软件测试5.1 根据程序执行状态…

DICOM医学影像应用篇——伪彩色映射 在DICOM医学影像中的应用详解

目录 引言 伪彩色映射的概念 基本原理 查找表&#xff08;Look-Up Table, LUT&#xff09; 步骤 示例映射方案 实现伪彩色映射的C代码 代码详解 伪彩色处理效果展示 总结 扩展知识 LUT 的基本概念 LUT 在伪彩色映射中的应用 示例 引言 在医学影像处理中&#xff0c…

韦东山stm32hal库--定时器喂狗模型按键消抖原理+实操详细步骤

一.定时器按键消抖的原理: 按键消抖的原因: 当我们按下按键的后, 端口从高电平变成低电平, 理想的情况是, 按下, 只发生一次中断, 中断程序只记录一个数据. 但是我们使用的是金属弹片, 实际的情况就是如上图所示, 可能会发生多次中断,难道我们要记录3/4次数据吗? 答:按键按下…

8、运算符

1、运算符相关概念 运算符&#xff1a; 具有一定运算规则的符号 运算符分类&#xff1a; 按照功能分&#xff1a; 赋值运算符 算术运算符 关系运算符 逻辑运算符 其他运算符 位运算符 按照操作数分&#xff1a; 单目运算符 双目运算符 三目运算符 表达式 具有一定意义的式子&…

【Linux网络编程】第二弹---Socket编程入门指南:从IP、端口号到传输层协议及编程接口全解析

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【Linux网络编程】 目录 1、Socket 编程预备 1.1、理解源 IP 和目的 IP 1.2、认识端口号 1.2.1、端口号范围划分 1.2.2、理解 &q…

算法训练营day08(字符串01:反转字符串,反转字符串2,替换数字,反转字符串里的单词,右旋转字符串)

第四章 字符串part01今日任务 ● 344.反转字符串 ● 541. 反转字符串II ● 卡码网&#xff1a;54.替换数字 ● 151.翻转字符串里的单词 ● 卡码网&#xff1a;55.右旋转字符串详细布置 344.反转字符串 建议&#xff1a; 本题是字符串基础题目&#xff0c;就是考察 reverse 函数…

Java中三种常用布局方式

引言 在Java Swing和JavaFX中&#xff0c;布局管理器&#xff08;Layout Managers&#xff09;用于控制组件&#xff08;如按钮、文本框等&#xff09;在容器&#xff08;如窗口、面板等&#xff09;内的位置和大小。下面介绍Java Swing中常用的三种布局方式&#xff1a; 1. Fl…

如何借助AI生成PPT,让创作轻松又高效

PPT是现代职场中不可或缺的表达工具&#xff0c;但同时也可能是令人抓狂的时间杀手。几页幻灯片的制作&#xff0c;常常需要花费数小时调整字体、配色与排版。AI的飞速发展为我们带来了革新——AI生成PPT的技术不仅让制作流程大大简化&#xff0c;还重新定义了效率与创意的关系…