MyBatis+Spring基于接口编程的原理分析

智能手环心率检测不准?用STM32+MAX30102教你实现医疗级精度(含算法优化) 本文详细解析了如何利用STM32微控制器和MAX30102光学传感器实现医疗级精度的心率检测方案。通过硬件参数调校、ADC采集优化、运动伪影消除及深度学习算法改进,显著提升智能手环在静态和运动状态下的检测精度,误差可控制在±1.5bpm以内,满足医疗电子标准。 阅读详情

http://www.iteye.com/topic/1060588

Java代码

 收藏代码

  1. package org.denger.mapper;  
  2.   
  3. import org.apache.ibatis.annotations.Param;  
  4. import org.apache.ibatis.annotations.Select;  
  5. import org.denger.po.User;  
  6.   
  7. public interface UserMapper {  
  8.   
  9.     @Select("select * from tab_uc_account where id=#{userId}")  
  10.     User getUser(@Param("userId") Long userId);  
  11. }  



application-context.xml:

Xml代码

 收藏代码

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
  6.   
  7.   
  8.     <!-- Provided by annotation-based configuration  -->  
  9.     <context:annotation-config/>  
  10.   
  11.     <!--JDBC Transaction  Manage -->  
  12.     <bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">  
  13.         <constructor-arg>  
  14.             <ref bean="dataSource" />  
  15.         </constructor-arg>  
  16.     </bean>  
  17.   
  18.     <!-- The JDBC c3p0 dataSource bean-->  
  19.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
  20.         <property name="driverClass" value="com.mysql.jdbc.Driver" />  
  21.         <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/noah" />  
  22.         <property name="user" value="root" />  
  23.         <property name="password" value="123456" />  
  24.     </bean>  
  25.   
  26.     <!--MyBatis integration with Spring as define sqlSessionFactory  -->  
  27.     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  28.         <property name="dataSource" ref="dataSource" />  
  29.     </bean>  
  30.   
  31.     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
  32.         <property name="sqlSessionFactory"  ref="sqlSessionFactory"/>  
  33.         <property name="basePackage" value="org.denger.mapper"></property>  
  34.     </bean>  
  35. </beans>  


test Class:

Java代码

 收藏代码

  1. package org.denger.mapper;  
  2.   
  3. import org.junit.Assert;  
  4. import org.junit.Test;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.test.context.ContextConfiguration;  
  7. import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;  
  8.   
  9. @ContextConfiguration(locations = { "/application-context.xml"})  
  10. public class UserMapperTest extends AbstractJUnit4SpringContextTests{  
  11.   
  12.     @Autowired  
  13.     public UserMapper userMapper;  
  14.       
  15.     @Test  
  16.     public void testGetUser(){  
  17.         Assert.assertNotNull(userMapper.getUser(300L));  
  18.     }  
  19. }  



实现原理分析
     对于以上极其简单代码看上去并无特殊之处,主要亮点在于 UserMapper 居然不用实现类,而且在调用 getUser 的时候,也是使用直接调用了UserMapper实现类,那么Mybatis是如何去实现 UserMapper的接口的呢?
    可能你马上能想到的实现机制就是通过动态代理方式,好吧,看看MyBatis整个的代理过程吧。
   
    首先在Spring的配置文件中看到下面的Bean:
   

Xml代码

 收藏代码

  1. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
  2.         <property name="sqlSessionFactory"  ref="sqlSessionFactory"/>  
  3.         <property name="basePackage" value="org.denger.mapper"></property>  
  4.     </bean>  


   以上的MapperScannerConfigurer class的注释中描述道:
   从base 包中搜索所有下面所有 interface,并将其注册到 Spring Bean容器中,其注册的class bean是MapperFactoryBean。
   好吧,看看它的注册过程,下面方法来从 MapperScannerConfigurer中的Scanner类中抽取,下面方法在初始化以上application-content.xml文件时就会进行调用。 主要用于是搜索 base packages 下的所有mapper class,并将其注册至 spring 的 benfinitionHolder中。
  

Java代码

 收藏代码

  1. /** 
  2. * Calls the parent search that will search and register all the candidates. Then the 
  3. * registered objects are post processed to set them as MapperFactoryBeans 
  4. */  
  5. @Override  
  6. protected Set<BeanDefinitionHolder> doScan(String... basePackages) {  
  7.         //#1  
  8.     Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);  
  9.     if (beanDefinitions.isEmpty()) {  
  10.             logger.warn("No MyBatis mapper was found in '" + MapperScannerConfigurer.this.basePackage  
  11.                         + "' package. Please check your configuration.");  
  12.     } else {  
  13.          //#2  
  14.          for (BeanDefinitionHolder holder : beanDefinitions) {  
  15.                 GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();  
  16.             if (logger.isDebugEnabled()) {  
  17.                 logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '"+ definition.getBeanClassName() + "' mapperInterface");  
  18.             }  
  19.            //#3  
  20.           definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());  
  21.           definition.setBeanClass(MapperFactoryBean.class);  
  22.      }  
  23.     return beanDefinitions;  
  24. }  

    #1: 了解Spring初始化Bean过程的人可能都知道,Spring 首先会将需要初始化的所有class先通过BeanDefinitionRegistry进行注册,并且将该Bean的一些属性信息(如scope、className、beanName等)保存至BeanDefinitionHolder中;Mybatis这里首先会调用Spring中的ClassPathBeanDefinitionScanner.doScan方法,将所有Mapper接口的class注册至BeanDefinitionHolder实例中,然后返回一个Set<BeanDefinitionHolder>,其它包含了所有搜索到的Mapper class BeanDefinitionHolder对象。

    #2: 首先,由于 #1:  中注册的都是接口class, 可以肯定的是接口是不能直接初始化的;实际 #2: 中for循环中替换当前所有 holder的 className为 MapperFactoryBean.class,并且将 mapper interface的class name setter 至 MapperFactoryBean 属性为 mapperInterface 中,也就是 #3: 代码所看到的。
  再看看 MapperFactoryBean,它是直接实现了 Spring 的 FactoryBean及InitializingBean 接口。其实既使不看这两个接口,当看MapperFactoryBean的classname就知道它是一个专门用于创建 Mapper 实例Bean的工厂。

  至此,已经完成了Spring与mybatis的整合的初始化配置的过程。

    接着,当我在以上的 Test类中,需要注入 UserMapper接口实例时,由于mybatis给所有的Mapper 实例注册都是一个MapperFactory的工厂,所以产生UserMapper实现仍需要 MapperFactoryBean来进行创建。接下来看看 MapperFactoryBean的处理过程。
    先需要创建Mapper实例时,首先在 MapperFactoryBean中执行的方法是:
 

Java代码

 收藏代码

  1. /** 
  2.      * {@inheritDoc} 
  3.      */  
  4.     public void afterPropertiesSet() throws Exception {  
  5.         Assert.notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");  
  6.         Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");  
  7.   
  8.         Configuration configuration = this.sqlSession.getConfiguration();  
  9.         if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {  
  10.             configuration.addMapper(this.mapperInterface);  
  11.         }  
  12.     }  

    上面方法中先会检测当前需要创建的 mapperInterface在全局的 Configuration中是否存在,如果不存在则添加。呆会再说他为什么要将 mapperInterface 添加至 Configuration中。该方法调用完成之后,就开始调用 getObject方法来产生mapper实例,看到MapperFactoryBean.getObject的该方法代码如下:
  

Java代码

 收藏代码

  1. /** 
  2.     * {@inheritDoc} 
  3.     */  
  4.    public T getObject() throws Exception {  
  5.        return this.sqlSession.getMapper(this.mapperInterface);  
  6.    }  

    通过Debug可以看到 sqlSession及mapperInterface对象:

    到目前为止我们的 UserMapper实例实际上还并未产生; 再进入org.mybatis.spring.SqlSessionTemplate中的getMapper方法,该方法将 this及mapper interface class 作为参数传入 org.apache.ibatis.session.Configuration的getMapper() 方法中,代码如下:
     

Java代码

 收藏代码

  1. /** 
  2.      * {@inheritDoc} 
  3.      */  
  4.     public <T> T getMapper(Class<T> type) {  
  5.         return getConfiguration().getMapper(type, this);  
  6.     }  


   于是,再进入 org.apache.ibatis.session.Configuration.getMapper中代码如下:
   

Java代码

 收藏代码

  1. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {  
  2.     return mapperRegistry.getMapper(type, sqlSession);  
  3.   }  

    其中 mapperRegistry保存着当前所有的 mapperInterface class. 那么它在什么时候将 mapperinterface class 保存进入的呢?其实就是在上面的 afterPropertiesSet 中通过 configuration.addMapper(this.mapperInterface) 添加进入的。
    再进入 org.apache.ibatis.binding.MapperRegistry.getMapper方法,代码如下:

Java代码

 收藏代码

  1. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {  
  2.   //首先判断当前knownMappers是否存在mapper interface class.因为前面说到 afterPropertiesSet 中已经将当前的 mapperinterfaceclass 添加进入了。  
  3.     if (!knownMappers.contains(type))  
  4.       throw new BindingException("Type " + type + " is not known to the MapperRegistry.");  
  5.     try {  
  6.       return MapperProxy.newMapperProxy(type, sqlSession);  
  7.     } catch (Exception e) {  
  8.       throw new BindingException("Error getting mapper instance. Cause: " + e, e);  
  9.     }  
  10.   }  


    嗯,没错,看到 MapperProxy.newMapperProxy后可以肯定的是它确实采用的代理模式,再进入一看究竟吧:
  

Java代码

 收藏代码

  1. public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {  
  2.     ClassLoader classLoader = mapperInterface.getClassLoader();  
  3.     Class[] interfaces = new Class[]{mapperInterface};  
  4.     MapperProxy proxy = new MapperProxy(sqlSession);  
  5.     return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);  
  6.   }  


   
    JDK的动态代理就不说了,至此,基本Mybatis已经完成了Mapper实例的整个创建过程,也就是你在具体使用 UserMapper.getUser 时,它实际上调用的是 MapperProxy,因为此时 所返回的 MapperProxy是实现了 UserMapper接口的。只不过 MapperProxy拦截了所有对userMapper中方法的调用,如下:
 

Java代码

 收藏代码

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  2.    try {  
  3.     //如果调用不是 object 中默认的方法(如equals之类的)  
  4.      if (!OBJECT_METHODS.contains(method.getName())) {  
  5.        //因为当前MapperProxy代理了所有 Mapper,所以他需要根据当前拦截到的方法及代理对象获取 MapperInterface  class,也就是我这里的 UserMapper.class  
  6.        final Class declaringInterface = findDeclaringInterface(proxy, method);  
  7.        //然后再根据UserMapper.class、及当前调用的Method(也就是getUser)及SqlSession构造一个 MapperMethod,在这里面会获取到 getUser方法上的 @Select() 的SQL,然后再通过 sqlSession来进行执行  
  8.        final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);  
  9.        //execute执行数据库操作,并返回结果集  
  10.        final Object result = mapperMethod.execute(args);  
  11.        if (result == null && method.getReturnType().isPrimitive()) {  
  12.          throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");  
  13.        }  
  14.        return result;  
  15.      }  
  16.    } catch (SQLException e) {  
  17.      e.printStackTrace();  
  18.    }  
  19.    return null;  
  20.  }  

     为什么说它拦截了呢?可以看到, 它并没有调用 method.invoke(object)方法,因为实际上 MapperProxy只是动态的 implement 了UserMapper接口,但它没有真正实现 UserMapper中的任何方法。至于结果的返回,它也是通过 MapperMethod.execute 中进行数据库操作来返回结果的。 说白了,就是一个实现了 MapperInterface 的 MapperProxy 实例被MapperProxy代理了,可以debug看看 userMapper实例就是 MapperProxy。

QNX Neutrino 进程间通信编程之Message-passing/Pulse Interprocess Communication(IPC,进程间通信)在QNX Neutrino从一个嵌入式实时系统向一个全面的POSIX系统转变起着至关重要的作用。IPC是将在内核中提供各种服务的进程内聚在一起的粘合剂。在QNX中,消息传递是IPC的主要形式,也提供了其他的形式,除非有特殊的说明,否则这些形式也都是基于本地消息传递而实现的。本篇幅主要讲解Message-passing和Pulse。 阅读详情

相关推荐

ComfyUI实战:AnimateDiff与ControlNet结合,打造无缝风格化视频转绘

本文详细介绍了如何利用ComfyUI平台,结合AnimateDiff与ControlNet插件,实现高质量的视频风格化转绘。通过搭建节点工作流、调整关键参数,有效解决画面闪烁与失真问题,并分享了进阶玩法与常见问题解决方案,帮助用户轻松打造流畅、风格统一的动态视觉效果。

weixin_29039773的博客 334

Spring整合Mybatis(基于Dao层接口实现类)

Spring整合Mybatis笔记,鉴于网上的资料鱼龙混杂,查看到的部分资料甚至把我带进沟里了,特此自己动手记录笔记: 首先我们知道常规的Mybatis使用基础需要定义一个Mybatis配置文件,一个Mapper映射文件,然后在需要用到的地方读取配置文件,代码如下: 首先我们的数据库很简单,如下: 表名为account 列名分别为id,name,money 对应的实体类如下: pac...

jnzisnoone的博客 2175

【架构设计】DDD 到底解决了什么问题

DDD作为架构设计思想帮助微服务控制规模复杂度,那它是怎么做到的呢?第一章提出了架构的根本目是解决系统复杂度,并简要说明系统复杂度的六个来源及通用解法,为我们设计架构提供了清晰可执行的操作思路。

DreamSun的博客 1158

springmvc和mybatis结合 可以直接把用mybatis写的接口注入到service层

http://bbs.youkuaiyun.com/topics/390773239今天我看别人用springmvc和mybatis结合的代码  以前我用SSH框架的 发现了个问题 public interface MmMapper {public List&lt;HashMap&lt;String, Object&gt;&gt; mmQueryByPage(@Param("mm")HashMap&lt;St...

lppl010_的专栏 2567

Xiaojie雷达之路---毫米波雷达基础知识---中频信号的相位

本篇文章主要介绍毫米波雷达的基础知识中的中频信号的相位 文章目录傅里叶变换的快速回顾中频信号的相位中频信号对物体微小位移的灵敏度如何2个chirps来对一个物体的速度进行测量测量一个振动的物体 傅里叶变换的快速回顾 傅里叶变换是将一个信号从时域中转换到频域中,在时域中的一个正弦信号将在频域中产生一个峰值,在大多数情况下,在频域中的一个信号是一个复数(每个值是一个振幅和相位的向量),表示为AejθAe^{j\theta}Aejθ 在频域中峰值的相位等于正弦函数的初始相位 中频信号的相位 上一篇文章中提到,

XiaoJie的博客 1万+

头歌操作系统 课堂练习4.2:页式内存管理 答案 无解析

头歌操作系统 课堂练习4.2:页式内存管理 答案 无解析

kercii的博客 1万+

MyBatis与Spring Mapper接口方式的开发整合

在传统的DAO开发方式可以实现所需功能,但是采用这种方式在实现类中会出现大量的重复代码。在映射文件中执行语句的id,并不能保证编写时id的正确性(运行时才能知道),这时候,就用到了Mapper接口编程。一、基于MapperFactoryBean的整合1.在src目录下创建 com.kangxg.mapper 包 并创建CustomerMapper接口文件及CustomerMapper.xml映射文...

圣人男的博客 3028

ARKit面部动画实战:如何用blend shape让数字人表情更自然(附中文对照表)

本文深入探讨了如何利用ARKit的blend shape技术驱动数字人面部动画,以实现更自然生动的表情。文章提供了详细的blend shape中文对照表,并分享了实战技巧,包括构建复合表情动画序列、处理不对称性与微表情,以及性能优化策略,旨在帮助开发者高效提升数字人的表情表现力。

weixin_29292535的博客 324

MyBatis+Spring 基于接口编程的原理分析

整合Spring3及MyBatis3 application-context.xml Test Case 实现原理分析 整合Spring3及MyBatis3 对于整合Spring及Mybatis不作详细介绍,可以参考: MyBatis 3 User Guide Simplified Chinese.pdf,贴出我的主要代码如下: package org.denger.mappe...

RodJohnson_523391的专栏 123

【FPGA教程案例59】深度学习案例6——基于FPGA的CNN卷积神经网络之整体实现

在课程,我们对的基本原理有了初步认识。在上一个课程,我们完成了CNN的Relu激活层、pool池化层、卷积层以及图像输入层的实现,如下图所示:在本课程中,我们将上述四个模块结合起来,构建一个简单的CNN卷积神经网络。...

FPGA/MATLAB学习教程/源码/项目合作开发 2634

AgentScope实战训练营-Java开发HITL人机协作AI应用完整指南

本文手把手带你从零搭建一个基于 Spring Boot WebFlux + AgentScope + 通义千问的人机协作(HITL)AI 聊天应用。项目涵盖流式对话、工具调用、高危操作确认、对话中断、动态 MCP 工具接入、中英文双语界面等完整功能。文章从环境准备、pom.xml 配置、DTO 数据模型、Hook 机制、AgentService 核心服务、ChatController 接口到前端 HTML/CSS/JS 实现,逐一讲解每行代码的设计意图,并附带 REST API 接口说明、测试场景、常见问题

program哲学 712

转 MyBatis+Spring 基于接口编程的原理分析

整合Spring3及MyBatis3 application-context.xml Test Case 实现原理分析 整合Spring3及MyBatis3 对于整合Spring及Mybatis不作详细介绍,可以参考: MyBatis 3 User Guide Simplified Chinese.pdf,贴出我的主要代码如下: package org.denger

JJYY778899的专栏 716

磁环电感参数计算

电感饱和是指当电感中的电流超过一定阈值时,电感中的磁场无法继续增加,而是达到一个饱和状态,导致电感的感应电动势减小或消失。电感通常由线圈组成,当通过线圈的电流不断增加时,线圈内部的磁场也随之增加。然而,当电流达到一定程度时,线圈的铁芯磁化达到饱和,无法进一步增加磁场强度。电感饱和的阈值取决于电感的结构、材料和尺寸等因素。通常情况下,电感的额定电流会标明其饱和电流值。一旦电感中的电流超过了饱和电流,电感将饱和并出现异常行为。当我们谈论电感饱和的时候,实际上是在谈论磁芯饱和——空心的电感永远不会饱和。

小幽余生不加糖 4028

MyBatis+Spring基于接口编程的原理分析(Mapper)

package org.denger.mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.denger.po.User; public interface UserMapper { @Select("selec...

zengshaotao的专栏 235

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

spring的基本介绍(基于学生管理平台)

基础的spring技术在项目中的应用

BELeeter123的博客 1616

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: 聊聊高并发系统之限流特技
下一篇: springboot EnableAutoConfiguration
god_love_hlq_xff
博客等级 码龄11年 27粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值