spring(二)-----------如何注入bean

news2024/9/29 11:31:01

我们从第三方框架mybatis为引,看看如何往spring中注入一个bean

1、纯mybatis开发生成一个mapper对象

如果不使用spring的情况下,mybatis想生成一个mapper对象大概需要做下面的操作:

假设我们有了一个TMapper接口,此时获取该mapper对象

SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(configuration);
SqlSession sqlSession = sqlSessionFactory.openSession();
TMapper mapper = sqlSession.getMapper(TMapper.class);

通过sqlsession.getMapper()即可获取mapper对象,但我们知道TMapper是一个接口,接口是不能进行实例化的,那这个对象是怎么来的?

如果翻阅mybatis源码会看到,底层对该接口进行了jdk动态代理完成了对象的实例化,最后返回了代理对象。

 好了,到这里我们大概知道mybatis生成一个mapper对象了,下面我们需要考虑的是如何将这个mapper对象注入到spring容器中。

2、如何将mapper对象注入到spring容器中

我们先不看mybatis如何将mapper对象注入到spring中去的,我们先来看看我们已知的可以往spring注入对象的方式。

注意:往spring中注入类和注入对象是不同的概念,注入类是spring会接管类对象实例化、初始化等过程,而注入对象则是将对象的实例化初始化交由自己掌控。

1)、@Component注解方式——这种方式是把类给spring管理

2)、xml方式,<bean id="" class="" ——同理这种方式也是把类给spring管理

3)、动态注册beanDefifinition——这种方式是把beanDefifinition对象给spring,并不是自己产的真实对 象 。

        以上三种方式会被很多人误解可以把一个对象给到spring容器;当然这三种方式最后也是产生了一个对 象,并且存到了容器当中;但是问题的关键是这个对象的产生过程是我们无法去控制的;是由spring容 器去实例化的对象;比如上面我们的tMapper对象,是需要我们用动态代理这种特定方式来产生, spring肯定不会帮你完成。所以再来看下下面的三种方式:

4)、@Bean方式——通过在方法当中编码,可以自己产生对象;返回后即存在容器,符合要求。

5)、FactoryBean方式——通过实现FactoryBean接口也可以自己编码产生对象,符合要求。(只是能实现对mapper对象进行实例化,但注入spring需要借助xml配置、其他注解等其他方式注入到spring中)

6)、使用spring提供的api,beanFactory.registerSingleton(String name,Object object)——直接传自己的对象 符合要求

那么mybatis中是如何去选择的?(下面以xml的方式去解析整体流程)

我们可以看看mybatisxml怎么去配一个mapper的:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
mybatis 开发了一个 MapperFactoryBean ,在他的 getObject 方法当中产生了代理对象;代理对象实现 接口通过属性注入进去,即上面代码中的org.mybatis.spring.sample.mapper.UserMapper
精简后的 MapperFactoryBean 源码:
public class MapperFactoryBean implements FactoryBean{
    
    private Class mapperInterface; //接收不同类型的mapper

    //返回代理对象
    public T getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface);
    }

    //xml配置的时候,提供Mapper,实现代理
    public void setMapperInterface(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
}

mybatis选择的是FactoryBean的方式。

FactoryBean 是一个特殊接口,实现了 factoryBean 的接口通常会产生两个 bean ,第一个实现类本身的 对象,第二个是getObject方法当中返回的对象; 此时就会往spring注入一个 MapperFactoryBean  (注入类方式)、一个mapper(注入对象方式,xml配置的时候会进行注入)。

        但是这个时候问题又来了,如果我要注入多个mapper对象,此时需要去xml配置多次?这会不会显得太麻烦了?此时基于FactoryBean的基础上(为了使得接口能被实例化、Mapper所有方法基本执行相同的操作——找到对应的SQL,绑定参数,执行SQL然后返回结果),我们需要解决多个mapper对象注入简易化的需求。

此时mybatis就抛弃了xml注入bean的配置化方式,提供了两个注解@MapperScan、@Mapper

@Mapper是队单个接口类的注解,单个操作,然后接口在编译之后都会生成相应的实现类。(接口少的时候适合使用,所以我们暂时不说他)

@MapperScan是对整个包之下的所有的接口类的注解,是批量的操作。使用@MapperScan之后,接口类就不需要再使用@Mapper注解了(正解决了注入多个mapper的简易化需求)

所以我们下面就得去看看@MapperScan是如何实现这么个过程的。

注意:FactoryBean+@Component并不能注入mapper对象,因为@Component只能将类交给spring生成bean,不能将对象交给spring。所以就不需要讨论这种情况了。而@Bean、beanFactory.registerSingleton()每配一个mapper就要编写一次,显然也不合适,所以就只剩下动态注册beanDefifinition。我们暂且不下定论,先看看mybatis是怎么做的。

3、@MapperScan如何进行多个mapper的注入

        在说明@MapperScan注解的原理前,需要明白的一点,就是要满足接口能被实例化、接口方法能执行相应逻辑的前提,保证这一前提的是使用了FactoryBean方式在getObject()方法中返回了一个jdk动态代理实例化好的的mapper代理对象。有了这一前提我们才需要解决多mapper注入的问题。

        由上面可知FactoryBean+xml配置可以将对象注入到spring中,不过这种情况在需要注入多个mapper的时候显得太麻烦了,所以mybatis就提供了一个扫描mapper的注解@MapperScan

Mybatis的mapper对象注入到Spring容器中的过程_DanceDonkey的博客-CSDN博客_mybatis mapper注入

我们可以点进@MapperScan注解中:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class) //在一个类、方法、属性上标注多个相同注解
public @interface MapperScan {}

 可以看到一个@Import({MapperScannerRegistrar.class}),@Import注解是用来导入配置类或者一些需要前置加载的类。

对于@MapperScan注解的原理可以看下面文章:

通过@MapperScan源码了解Spring自定义注解扫描器[通俗易懂] - 腾讯云开发者社区-腾讯云

看过这篇文章,可以知道,mybatis确实是使用了动态注册beanDefifinition的方式将FactoryBean方式产生的mapper代理对象注入到了spring中。

那么我们下面需要看看什么是beanDefifinition、如何动态注册beanDefifinition?

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

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

相关文章

12款开源数据资产(元数据)管理平台选型分析(三)

如上&#xff0c;是ChatGPT的百度指数和微信指数&#xff0c;继2022年12月上旬技术圈火热之后&#xff0c;因为微软、谷歌等巨头的推广加持&#xff0c;ChatGPT成为全球大众热源的话题。各大媒体都在消费这波舆论红利&#xff0c;打开微信公众号&#xff0c;劈天盖地各种姿势的…

前后端学习

最近和锴哥想搞一下前后端接口的事儿&#xff0c;但是不会&#xff0c;所以打算再学学前后端的基础知识&#xff0c;之后好抄作业&#xff0c;做缝纫机&#xff1b;达哥觉得我浮躁&#xff0c;这次一定要支棱起来&#xff1b;这次开始&#xff0c;面向openai学习。 前后端学习1…

ChatGPT (可能)是怎么炼成的

学习自李宏毅老师的课https://www.youtube.com/watch?ve0aKI2GGZNg 1.学习文字接龙 学习方式 GPT只需要在网上阅读大量的句子&#xff0c;不需要人工标注即可学习到大量句子接龙的知识 然而实际上&#xff0c;“你好”后面可以接的字有很多。实际上&#xff0c;GPT学的就是…

3、Go基础数据类型

目录一、Go数据类型二、字符串三、强制类型转换一、Go数据类型 基础数据类型 类型长度(字节)默认值说明bool1falsebyte10uint8&#xff0c;取值范围[0,255]rune40Unicode Code Point, int32int, uint4或8032 或 64 位&#xff0c;取决于操作系统int8, uint810-128 ~ 127, 0 ~…

Freemarker介绍

2. Freemarker介绍 FreeMarker 是一个用 Java 语言编写的模板引擎&#xff0c;它基于模板来生成文本输出。FreeMarker与 Web 容器无关&#xff0c;即在 Web 运行时&#xff0c;它并不知道 Servlet 或 HTTP。它不仅可以用作表现层的实现技术&#xff0c;而且还可以用于生成 XML…

Python数据结构:概念、栈

1.概念 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。简单来说&#xff0c;数据结构就是设计数据以何种方式组织并存储在计算机中。 比如:列表、集合与字典等都是一种数据结构。 N.Wirth:“程序数据结构算法’ 2.分类 数据结…

基于comsol软件弯曲单模光纤模拟仿真

在本节中&#xff0c;主要基于实验室实际光纤单模圆柱光纤进行模拟&#xff0c;与comsol案例库文件在分析过程和建模有些差异&#xff1a; 模拟主要通过以下三个步骤进行&#xff1a;模型的几何构建、物理场的添加研究、结构处理分析来进行。 下面是第一步骤&#xff1a;几何…

unity2022.1.8之后版本的新的输入行为控制对象变化

文章目录unity2022.1.8之后版本的新的输入行为控制对象变化怎么导入&#xff1f;如何使用&#xff1f;unity2022.1.8之后版本的新的输入行为控制对象变化 我们先了解大概的逻辑。我们要设置触发行为的方式并且让他和对象的行为绑定&#xff0c;再将行为和对象绑定&#xff0c;…

SpringBoot开发规范部分通用模板+idea配置【项目通用-1】

SpringBoot开发规范通用模板 1 分页插件使用 通过MybatisPlus配置分页插件拦截器 Configuration MapperScan("com.xuecheng.content.mapper") public class MybatisPlusConfig {//定义分页的拦截器Beanpublic MybatisPlusInterceptor getMybatisPlusInterceptor() {…

Pascal版本的 - freopen

参数 filename -- 这是包含要打开的文件的名称的字符串。 mode -- 这是包含文件访问模式的字符串。它包括 - 高级编号模式&说明1个 “r” 打开文件进行读取。该文件必须存在。 2个 “w” 创建一个用于写入的空文件。如果已存在同名文件&#xff0c;则删除其内容并将该文件…

【Java容器(jdk17)】ArrayList深入源码,就是这么简单

ArrayList深入源码一、ArrayList源码解析1. MIXIN 的混入2. 属性说明3. 构造方法4. 其他方法&#xff08;核心&#xff09;iterator 和 listIterator 方法add方法remove 方法sort方法其他二、ArrayList 为什么是线程不安全的&#xff1f;体现哪些方面呢&#xff1f;三、ArrayLi…

(day12) 自学Java——集合进阶(双列集合)

目录 1.双列集合特点 Map遍历三种方式 2.HashMap 3.LinkedHashMap 4.TreeMap 5.源码解析 6.可变参数(形参个数可变) 7.Collections 8.综合练习 1.双列集合特点 ①双列集合一次需要存一对数据&#xff0c;分别为键和值 ②键不能重复&#xff0c;值可以重复 ③键和值是一…

全志H616——用C语言的形式操作数据库

sqlite3_open(const char *filename, sqlite3 **ppDb)该例程打开一个指向 SQLite 数据库文件的连接&#xff0c;返回一个用于其他 SQLite 程序的数据库连接对象。sqlite3_close(sqlite3*)该例程关闭之前调用 sqlite3_open() 打开的数据库连接。所有与连接相关的语句都应在连接关…

【Linux】环境变量本地变量

文章目录环境变量基本概念常见环境变量和环境变量相关的命令为什么带./运行我们的可执行程序本地变量环境变量的组织方式环境变量具有全局属性环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如&#xff1a;我们…

gRPC的简单应用

gRPC的简单应用 gRPC是由开发的一个高性能、通用的开源RPC框架&#xff0c;主要面向移动应用开发且基于HTTP/2协议标准而设计&#xff0c;同时支持大多数流行的编程语言。 官网&#xff1a;https://grpc.io/ 安装protoc 工具 https://protobuf.dev/ 安装Go插件 旧版本直接…

学习HandlerThread

HandlerThread是一个扩展了Thread的类。也就意味着它和普通的Thread类的调用没有什么区别&#xff0c;仍然要调用start()。 如上图所示&#xff0c;扩展后的HandlerThread类有一个Looper和Handler。 关于这一块的知识可以参考一下《关于Handler我们应该知道的知识》 HandlerTh…

普冉PY32系列(五) 使用JLink RTT代替串口输出日志

目录 普冉PY32系列(一) PY32F0系列32位Cortex M0 MCU简介普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单普冉PY32系列(四) PY32F002A/003/030的时钟设置普冉PY32系列(五) 使用JLink RTT代替串口输出日志 JLink …

Python-第五天 Python函数

Python-第五天 Python函数一、函数介绍1. 什么事函数二、函数的定义1.函数的定义&#xff1a;2.案例三、函数的参数1.函数的传入参数2.案例升级四、函数的返回值1.什么是返回值2.返回值的语法3.None类型4.None类型的应用场景五、函数说明文档1.函数的说明文档2.在PyCharm中查看…

脑机接口协议V1.0

脑机接口&#xff0c;有时也称作“大脑端口”direct neural interface或者“脑机融合感知”brain-machine interface&#xff0c;它是在人或动物脑&#xff08;或者脑细胞的培养物&#xff09;与外部设备间建立的直接连接通路。在单向脑机接口的情况下&#xff0c;计算机或者接…

leaflet显示高程

很多地图软件都能随鼠标移动动态显示高程。这里介绍一种方法&#xff0c;我所得出的。1 下载高程数据一般有12.5m数据下载&#xff0c;可惜精度根本不够&#xff0c;比如mapbox的免费在线的&#xff0c;或者91卫图提供百度网盘打包下载的&#xff0c;没法用&#xff0c;差距太大…