前言

大家好,我是 god23bin,今天继续说 Spring 的内容,关于 Spring 中 Bean 的配置的,通过上一篇文章的学习,我们知道了 Spring 中的依赖注入,其中有两种主要的方式,分别是基于构造方法的 DI基于 Setter 的 DI

我们知道,当写完一个普通的 Java 类后,想让 Spring IoC 容器在创建类的实例对象时使用构造方法完成实例对象的依赖注入,那么就需要在配置元数据中写好类的 Bean 定义,包括各种标签的属性。

如果你是第一次看我这个系列的文章,可能不知道什么是配置元数据,不知道什么是依赖注入,那么请你先去看看我之前的文章,相信对你是有帮助的~

现在我们来说说这其中的配置细节,废话不多说,开始啦!

Bean 定义中的基本标签

property

property 标签:用于注入简单属性值,可以通过 name 属性指定属性名称,通过 value 属性指定属性值,或者通过 ref 属性指定引用其他 Bean。

<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee">
<property name="id" value="1" />
<property name="name" value="god23bin" />
<property name="department" ref="department" />
</bean> <bean id="department" class="cn.god23bin.demo.domain.entity.Department">
<property name="id" value="1" />
<property name="name" value="JUST DO IT" />
</bean>

constructor

constructor 标签:使用构造方法参数值进行注入。通过 value 属性指定了参数的具体值,或通过 ref 属性指定了对其他 Bean 的引用。这样,在容器创建 Bean 实例时,会使用指定的参数值调用构造方法,实现构造方法注入。

<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee">
<constructor-arg value="1" />
<constructor-arg value="god23bin" />
<constructor-arg ref="department" />
</bean> <bean id="department" class="cn.god23bin.demo.domain.entity.Department">
<constructor-arg value="1" />
<constructor-arg value="JUST DO IT" />
</bean>

list

list 标签:用于注入 List 集合类型的属性值,可以通过value 子标签指定元素的值,或者通过 ref 子标签指定引用其他 Bean。

<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee">
<property name="skills">
<list>
<value>Java</value>
<value>Spring</value>
<value>MySQL</value>
</list>
</property>
<property name="departments">
<list>
<ref bean="department" />
</list>
</property>
</bean> <bean id="department" class="cn.god23bin.demo.domain.entity.Department">
<constructor-arg value="1" />
<constructor-arg value="JUST DO IT" />
</bean>

set

set 标签:用于注入 Set 集合类型的属性值,用法和 list 标签类似。

<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee">
<property name="setProperty">
<set>
<value>Value 1</value>
<ref bean="bean1"/>
<ref bean="bean2"/>
</set>
</property>
</bean>

map

map 标签:用于注入 Map 集合类型的属性值,可以通过 entry 子标签指定键值对,键可以通过 key 属性指定,值可以通过 value 属性指定,或者通过 ref 子标签指定引用其他Bean。

<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee">
<property name="mapProperty">
<map>
<entry key="key1" value="Value 1"/>
<entry key="key2">
<ref bean="bean1"/>
</entry>
</map>
</property>
</bean>

props 标签:用于注入 Properties 类型的属性值,可以通过 prop 子标签指定键值对,键可以通过 key 属性指定,值可以通过 value 属性指定。

<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee">
<property name="propsProperty">
<props>
<prop key="key1">Value 1</prop>
<prop key="key2">Value 2</prop>
</props>
</property>
</bean>

以上是 Spring XML 配置文件中 Bean 注入的常用标签和集合注入的标签。

depend-on 的使用

正常情况下,举个例子:

public class A {
private B b; // 省略 getter 和 setter
}

B 这个 Bean 被写成是 A 的属性,也就是说,A 类依赖 B 类,这种正常的依赖关系下,我们在以 XML 为配置元数据的配置文件中,可以使用 ref 属性来指定 A 的依赖项是 B。

<bean id="a" class="cn.god23bin.demo.domain.model.A">
<property name="b" ref="b" />
</bean> <bean id="b" class="cn.god23bin.demo.domain.model.B"/>

这种依赖关系,是很明显的,一下子就能看出 A 是依赖 B 的,所以我们可以使用 ref 属性来指定依赖项,与此同时,这个依赖项会被注入到需要它的 Bean 中,这里就是 B 的对象被注入到 A 中作为 b 属性。

那么对于依赖关系不明显,但是又有依赖关系的时候,就可以使用 depend-on 属性。

比如有一个类 C,它是间接依赖 D 类的,也就是说 D 没有作为 C 的属性。此时,想要实例化 C,那么需要 D 先实例化好后,才能去实例化 C。

<bean /> 标签中的 depend-on 属性就能够做到这一点,让这种依赖关系不明显的,也能保证你在使用某个 Bean 时,该 Bean 的依赖项会先实例化。

<!-- 使用 depend-on 属性指定 C 这个 Bean 是依赖于 D 的 -->
<bean id="c" class="cn.god23bin.demo.domain.model.C" depend-on="d" /> <bean id="d" class="cn.god23bin.demo.domain.model.D" />

这样,在使用 C 时,是能够保证 C 的依赖项 D 是已经实例化好的。

如果有多个依赖项,那么可以使用有效的分隔符进行分割(英文逗号、英文分号或者空格):

<!-- 使用 depend-on 属性指定 C 这个 Bean 是依赖于 D 的 -->
<bean id="c" class="cn.god23bin.demo.domain.model.C" depend-on="d,another" /> <bean id="d" class="cn.god23bin.demo.domain.model.D" />
<bean id="another" class="cn.god23bin.demo.model.Another" />

同理,销毁对象的时候,在销毁 C 对象之前,D 就会被先销毁。

lazy-init 的使用

<bean /> 标签中的 lazy-init 属性是用来指定某个 Bean 是否开启懒加载的。

默认情况下,Bean 定义中这个属性默认值是 false,也就是说默认的 Bean 都不是懒加载的,当 Spring IoC 容器创建后,容器就会立即去创建并完全配置所有的单例作用域的 Bean。

如果我们想让某个 Bean 不在一开始就被实例化,那么就可以使用这个懒加载属性开启某个 Bean 的懒加载。懒加载的 Bean,只有在被第一次使用时,才会被实例化。

在以 XML 为配置元数据为例,直接使用 lazy-init 属性,设置该属性为 true 就 OK。

<bean id="lazyBean" class="cn.god23bin.demo.domain.model.LazyBean" lazy-init="true" />

当然,如果这个懒加载的 Bean 被其他没有懒加载的单例 Bean 给引用了,那么这个懒加载的 Bean 也会在容器创建后被容器所创建,因为容器必须确保单例 Bean 的依赖项都被实例化了。

自动注入依赖项

Spring 支持 Bean 之间依赖关系的自动注入。 它能根据 ApplicationContext 的内容帮我们处理 Bean 之间的依赖关系,这样我们就可以不用手动在配置元数据中指定 Bean 之间的依赖关系。

网上有很多博客把「自动注入」说成「自动装配」的,在我看来,这是两回事,实际上从它们的英文名来看,就是两回事。

说到自动装配(Auto Configuration),一般都是联系到 Spring Boot 的,因为它的特点就是开箱即用,省去大量的配置,而之所以能省去大量的配置,就得益于它的自动装配。而自动注入(Autowiring Collaborator)是指自动注入协作者,换句话说,指 Bean 之间的依赖项 Spring 能帮你去注入。

自动注入的优点

  • 可以大大减少我们在配置元数据中进行指定属性或构造方法的参数

  • 可以随着对象的发展而更新配置,比如你需要给某个类添加一个新的依赖项,那么你不需要去修改配置元数据,自动注入就帮我们处理

以 XML 作为配置元数据的情况下,我们可以使用 <bean /> 标签中的 autowire 属性来指定自动注入的模式。

3 种自动注入的模式

默认没有自动注入,这就是最开始学习的写法,Bean 的依赖项需要用 ref 属性来指定。

  1. byName:容器会默认根据属性名找到一个同名的 Bean 进行自动注入。
<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee" autowire="byName">
<!-- 属性 -->
</bean>
  1. byType:容器会默认根据属性的类型找到一个同类型的 Bean 进行自动注入,如果存在多个同类型的 Bean,那么 Spring IoC 容器就不知道注入哪一个 Bean,就会抛出异常。
<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee" autowire="byType">
<!-- 属性 -->
</bean>
  1. constructor:类似 byType,不过它是基于构造方法参数的自动注入。
<bean id="employee" class="cn.god23bin.demo.domain.entity.Employee" autowire="constructor">
<!-- 构造函数参数 -->
</bean>

需要注意的是,自动注入只对那些具有依赖关系的 Bean 起作用,而不是所有的 Bean。因此,在配置 Bean 的时候,需要确保被注入的属性在其他 Bean 中是存在的。

自动注入的限制和缺点

  • 在配置元数据中,使用 <property /><constructor-args /> 编写的明确的依赖关系会覆盖自动注入的,换句话说,它的优先级比自动注入的方式高。还有就是自动注入是不能注入简单的类型的,比如基本数据类型、String、Class 等类型(包括这些类型的数组也是不能自动注入的)。这里的限制是设计上的限制。
  • 自动注入是单靠 Spring 帮我们注入的,精确度不如我们手动去明确设置 Bean 之间的依赖关系的,某些情况下可能由于我们的疏忽会注入错误的 Bean 导致意想不到的结果。
  • 自动注入的信息对于一些用来生成文档的工具可能是没用的。
  • 自动注入的时候找到了多个匹配上的 Bean,对于数组和集合来说是正常的,没什么问题,但是如果要注入的 Bean 是单值属性的依赖关系,那么 Spring IoC 就不知道该注入哪一个 Bean,就会抛出异常。这个就在上面的 byType 中说过的。

对于自动注入匹配到了多个 Bean,有以下解决方案:

  • 不用自动注入,改为明确手动注入
  • 使用 <bean /> 中的 primary 属性,设置为 true,那么在多个同类型的 Bean 定义当中,如果匹配上了,那么这个 Bean 就是主要的候选者,就会注入这个 Bean。
  • 使用基于注解的自动注入(@Autowired@Primary 等)

这几个使用注解实现自动注入的,在后面的文章中再讲。

总结

我们总结一下,关于 Spring 中 Bean 的配置与依赖注入的重要内容。

  • Bean 的配置元数据可通过 XML 文件进行定义和配置,当然后续我们会介绍使用注解Java 配置作为配置元数据的方式。
  • 基本标签包括 propertyconstructor-arglistsetmapprops,用于注入属性值或集合类型的属性。
  • depend-on 属性用于指定 Bean 之间的依赖关系,确保指定的 Bean 先于当前 Bean 实例化,这种依赖不是显式的依赖。
  • lazy-init 属性用于指定 Bean 是否懒加载,默认为 false,即容器启动时立即实例化所有单例 Bean。
  • 自动注入可减少配置元数据中的显式指定依赖项,提供 autowire 属性以设置自动注入的模式。
  • 自动注入模式包括 byNamebyTypeconstructor,通过属性名或类型进行自动匹配完成依赖注入。
  • 自动注入存在一定的限制和缺点,需注意配置的精确性和冲突解决。
  • 对于多个匹配的自动注入,可通过手动注入、primary 属性或基于注解的自动注入来解决。

以上就是本篇所有的内容了,对屏幕前的你有帮助的话,麻烦点点关注,点个免费的赞,给予我支持与鼓励,感兴趣的话可以关注我这个专栏,谢谢你们!

最后的最后

希望各位屏幕前的靓仔靓女们给个三连!你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

咱们下期再见!

Spring 中 Bean 的配置细节的更多相关文章

  1. spring中bean的配置详解--定义parent

    在工作中碰到了好多的配置文件,具体来说是spring 中bean配置的parent的配置,搞的我一头雾水,仔细看一下spring中有关bean的配置,剖析一下,具体什么含义! 一.Spring IoC ...

  2. Spring中Bean的配置:基于XML文件的方式

    Bean的配置一共有两种方式:一种是基于XML文件的方式,另一种是基于注解的方式.本文主要介绍基于XML文件的方式 <bean id="helloWorld" class=& ...

  3. Spring中bean的配置

    先从IOC说起,这个概念其实是从我们平常new一个对象的对立面来说的,我们平常使用对象的时候,一般都是直接使用关键字类new一个对象,那这样有什么坏处呢?其实很显然的,使用new那么就表示当前模块已经 ...

  4. Spring中Bean的配置:基于注解的方式

    组件扫描:Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件. 特定组件包括: -@Component:基本注解,标识一个受Spring管理的组件 -@Respositor ...

  5. 阶段3 2.Spring_03.Spring的 IOC 和 DI_6 spring中bean的细节之三种创建Bean对象的方式

    目前这里能调用是因为,在service的实现类里面,new了一个dao的对象 正常情况下 这里不应该是new一个对象,应该等于null或为空 设置为空侯再运行就会报错 出错的原因是这里为null 需要 ...

  6. Spring中三种配置Bean的方式

    Spring中三种配置Bean的方式分别是: 基于XML的配置方式 基于注解的配置方式 基于Java类的配置方式 一.基于XML的配置 这个很简单,所以如何使用就略掉. 二.基于注解的配置 Sprin ...

  7. 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章

    前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...

  8. Spring中Bean的作用域、生命周期

                                   Bean的作用域.生命周期 Bean的作用域 Spring 3中为Bean定义了5中作用域,分别为singleton(单例).protot ...

  9. Spring中Bean的实例化

                                    Spring中Bean的实例化 在介绍Bean的三种实例化的方式之前,我们首先需要介绍一下什么是Bean,以及Bean的配置方式. 如果 ...

  10. Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

随机推荐

  1. 面试官:服务器最大可以创建多少个tcp连接以及端口并解释下你对文件句柄的理解

    转载请注明出处: 1.最大可以创建多少个tcp连接 服务器最大可以创建多少个TCP连接取决于多个因素,例如服务器的硬件配置.网络带宽.操作系统设置等.一般来说,现代服务器的硬件资源和网络带宽都比较充足 ...

  2. 指针和引用(pointer and reference),传值和传址

    pass by adress pass by reference和pass by pointer的共同点都在于传址,都是对于对象的地址的复制,而不会对对象进行产生副本的操作. pass by refe ...

  3. uniapp directive 在原生 wgt 包不生效 uniapp directive 不生效

    需求 根据权限编码禁用按钮 阻止当前 dom 绑定的点击事件,禁用状态(opacity 半透明?? 或者 display: none?? ) 尝试 开发环境用 Chrome 跑,一切正常,构建打包后去 ...

  4. javasec(四)序列化与反序列化基本原理

    title: javasec(四)序列化与反序列化基本原理 tags: - javasec - 反序列化 categories: - javasec cover: 'https://blog-1313 ...

  5. [Pytorch框架] 2.1.1 PyTorch 基础 : 张量

    文章目录 PyTorch 基础 : 张量 张量(Tensor) 基本类型 Numpy转换 设备间转换 初始化 常用方法 PyTorch 基础 : 张量 在第一章中我们已经通过官方的入门教程对PyTor ...

  6. [OpenCV-Python] 13 颜色空间转换

    文章目录 OpenCV-Python:IV OpenCV中的图像处理 13 颜色空间转换 13.1 转换颜色空间 13.2 物体跟踪 13.3 怎样找到要跟踪对象的 HSV 值? OpenCV-Pyt ...

  7. MySQL WorkBench更换界面成中文的方法

    菜单页面更换 文章目录 菜单页面更换 汉化文件的xml文件我放在下面的网盘中了 1.找到MySQL的安装位置, 总结 汉化文件的xml文件我放在下面的网盘中了 1.找到MySQL的安装位置, 具体安装 ...

  8. 2020-01-25:redis中,哨兵如何选举?

    福哥答案2020-01-25: [答案1:](https://bbs.csdn.net/topics/398982967)redis-sentinel故障转移的流程:1.当多个sentinel发现并确 ...

  9. 2021-12-03:石子游戏 IV。Alice 和 Bob 两个人轮流玩一个游戏,Alice 先手。 一开始,有 n 个石子堆在一起。每个人轮流操作,正在操作的玩家可以从石子堆里拿走 任意 非零 平

    2021-12-03:石子游戏 IV.Alice 和 Bob 两个人轮流玩一个游戏,Alice 先手. 一开始,有 n 个石子堆在一起.每个人轮流操作,正在操作的玩家可以从石子堆里拿走 任意 非零 平 ...

  10. Midjourney|文心一格prompt教程[Text Prompt(上篇)]:品牌log、App、徽章、插画、头像场景生成,各种风格选择:科技风、运动风

    Midjourney|文心一格prompt教程[Text Prompt(上篇)]:品牌log.App.徽章.插画.头像场景生成,各种风格选择:科技风.运动风 1.撰写 Text Prompt 注意事项 ...