前言

大家好,我是 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. 多表查询和python操作mysql

    目录 多表查询的两种方法 方法1:连表操作 方法2:子查询 小知识点补充说明 可视化软件NaviCat 多表查询练习题 1.查询所有的课程的名称以及对应的任课老师姓名 2.查询平均成绩大于八十分的同学 ...

  2. [Java EE]SpringBoot/Tomcat之启动时报"Error: Could not find or load main class CLASS xxxx"、"no main manifest attribute"异常

    环境信息如下: OS: CENTOS 7 Tomcat : 9.0.46 SpringBoot: 2.3.12.RELASE Build JDK: 1.8.0_261 Runetime JDK : o ...

  3. SQL优化(二)-- 慢查询

    1.慢查询日志 MYSQL的慢查询日志是Mysql提供的一种日志记录方式,它主要是用来记录mysql执行语句过程中,响应时间超过阀值的语句,这个阀值可以通过long_query_time去指定,比如说 ...

  4. Linux网络管理入门

    根据自己的需要来设置Linux的一些属性 网络状态查看 在终端输入ifconfig可以查看网络状态 # ifconfig eth0: flags=4163<UP,BROADCAST,RUNNIN ...

  5. Locust 运行方式

      命令参数方式运行 # -*- coding: utf-8 -*- from locust import TaskSet, task, User ''' 命令行参数运行示例代码 ''' class ...

  6. Netty之数据解码

    一.概况 作为Java世界使用最广泛的网络通信框架Netty,其性能和效率是有目共睹的,好多大公司都在使用如苹果.谷歌.Facebook.Twitter.阿里巴巴等,所以不仅仅是因为Netty有高效的 ...

  7. Irwin-Hall 分布学习笔记

    定理:Irwin-Hall 分布 对于 \(n\) 个在 \([0,1]\) 内均匀分布的实数随机变量,它们的和不超过一个实数 \(z\) 的概率为: \[F(z)=\sum\limits_{k=0} ...

  8. AGC061 F Perfect String

    毒瘤出题人,史诗加强 AGC 的 F-- 然而我连原题都不会,所以只学了原题做法. 翻译一下题意就是给定一张循环网格图,求经过 \((0,0)\) 的闭合回路条数. 由于网格图中每一个位置都等价,所以 ...

  9. 聚合短信PHP代码示例短信接口调用CURL方法

    聚合的短信相信大家已经做多了吧,网上的代码看了下就是感觉太繁琐了,不过网上的也是比较好的,用的是post方法,更安全,因我们的项目是在服务器上请求,又绑定了白名单 ,所以弄了个简单点的自己用,参考如下 ...

  10. 2021-05-29:最常使用的K个单词II。在实时数据流中找到最常使用的k个单词,实现TopK类中的三个方法: Top

    2021-05-29:最常使用的K个单词II.在实时数据流中找到最常使用的k个单词,实现TopK类中的三个方法: TopK(k), 构造方法.add(word),增加一个新单词.topk(),得到当前 ...