当前位置: 首页 > news >正文

mybatis-spring @MapperScan走读分析

接上一篇文章:https://blog.csdn.net/qq_26437925/article/details/145100531, 本文注解分析mybatis-spring中的@MapperScan注解,则将容易许多。

目录

    • @MapperScan注解定义
    • ConfigurationClassPostProcessor扫描注册beanDefinition
    • org.mybatis.spring.mapper.MapperFactoryBean
    • org.apache.ibatis.binding.MapperProxy
      • org.apache.ibatis.executor.SimpleExecutor#doUpdate
    • 总结

@MapperScan注解定义

@MapperScan注解加入了@Import(MapperScannerRegistrar.class), 所以可以知晓

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {/*** Alias for the {@link #basePackages()} attribute. Allows for more concise* annotation declarations e.g.:* {@code @EnableMyBatisMapperScanner("org.my.pkg")} instead of {@code* @EnableMyBatisMapperScanner(basePackages= "org.my.pkg"})}.*/String[] value() default {};/*** Base packages to scan for MyBatis interfaces. Note that only interfaces* with at least one method will be registered; concrete classes will be* ignored.*/String[] basePackages() default {};/*** Type-safe alternative to {@link #basePackages()} for specifying the packages* to scan for annotated components. The package of each class specified will be scanned.* <p>Consider creating a special no-op marker class or interface in each package* that serves no purpose other than being referenced by this attribute.*/Class<?>[] basePackageClasses() default {};/*** The {@link BeanNameGenerator} class to be used for naming detected components* within the Spring container.*/Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;/*** This property specifies the annotation that the scanner will search for.* <p>* The scanner will register all interfaces in the base package that also have* the specified annotation.* <p>* Note this can be combined with markerInterface.*/Class<? extends Annotation> annotationClass() default Annotation.class;/*** This property specifies the parent that the scanner will search for.* <p>* The scanner will register all interfaces in the base package that also have* the specified interface class as a parent.* <p>* Note this can be combined with annotationClass.*/Class<?> markerInterface() default Class.class;/*** Specifies which {@code SqlSessionTemplate} to use in the case that there is* more than one in the spring context. Usually this is only needed when you* have more than one datasource.*/String sqlSessionTemplateRef() default "";/*** Specifies which {@code SqlSessionFactory} to use in the case that there is* more than one in the spring context. Usually this is only needed when you* have more than one datasource.*/String sqlSessionFactoryRef() default "";/*** Specifies a custom MapperFactoryBean to return a mybatis proxy as spring bean.**/Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;}

ConfigurationClassPostProcessor扫描注册beanDefinition

mybatis-spring中自定义了org.mybatis.spring.annotation.MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,所以能被处理

在这里插入图片描述
mybatis-spring也实现了自己的Scanner能够扫描出所有的@Mapper的interface, 然后定义出BeanDefinition

继续debug可以看到对BeanDefinisiton 会设置BeanClass为FactoryBean类在这里插入图片描述

即自定义的org.mybatis.spring.mapper.MapperFactoryBean

org.mybatis.spring.mapper.MapperFactoryBean

仍然是重点关注getObject方法

@Override
public T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);
}

数据库操作也封装为SqlSession接口,有多个实现类可选择
在这里插入图片描述

最后也会发现是java 动态代理
在这里插入图片描述

org.apache.ibatis.binding.MapperProxy

代理的具体实现则在mybatis依赖的MapperProxy类中

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else if (isDefaultMethod(method)) {return invokeDefaultMethod(proxy, method, args);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);
}

sql执行

public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result = executeForCursor(sqlSession, args);} else {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + command.getName());}if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");}return result;
}

org.apache.ibatis.executor.SimpleExecutor#doUpdate

继续深入找一个简单的sql执行实现类,可以看到类似jdbc的处理流程
在这里插入图片描述

总结

最后还是回到了上一篇博文:https://blog.csdn.net/qq_26437925/article/details/145100531。只不过mybatis-spring要丰富一些,原理仍然是动态代理BeanFactoryPostProcessorFactoryBeanBeanPostProcessor这些基础知识。

http://www.lryc.cn/news/520907.html

相关文章:

  • Mysql--架构篇--体系结构(连接层,SQL层,存储引擎层,文件存储层)
  • 【0x005B】HCI_Write_Default_Erroneous_Data_Reporting命令详解
  • 基于 Python 的学生成绩管理系统设计与实现
  • 【Apache Doris】周FAQ集锦:第 29 期
  • 【C】初阶数据结构3 -- 单链表
  • Autodl安装tensorflow2.10.0记录
  • 【Rust】常见集合
  • SpiderFlow平台v0.5.0之引入selenium插件
  • git push命令
  • 洛谷P1161
  • Python脚本自动发送电子邮件
  • vscode的安装与使用
  • sparkRDD教程之必会的题目
  • Unity 2d描边基于SpriteRender,高性能的描边解决方案
  • 信凯科技业绩波动明显:毛利率远弱行业,资产负债率偏高
  • js基础---var与let的区别以及const的使用
  • 用css和html制作太极图
  • OJ12:160. 相交链表
  • 软件工程和项目管理领域 - CMMI 极简理解
  • C# 线程基础之 线程同步
  • [c语言日寄]c语言也有“回”字的多种写法——整数交换的三种方式
  • RocketMQ 知识速览
  • 优化 Azure Synapse Dedicated SQL Pool中的 SQL 执行性能的经验方法
  • 详解英语单词“pro bono”:公益服务的表达(中英双语)
  • 16. C语言 字符串详解
  • 使用Buildroot开始嵌入式Linux系统之旅-3
  • [免费]SpringBoot+Vue新能源汽车充电桩管理系统【论文+源码+SQL脚本】
  • 【已解决】【记录】2AI大模型web UI使用tips 本地
  • 44.ComboBox的数据绑定 C#例子 WPF例子
  • 物联网之传感器技术