Spring(03)——依赖注入

简介: 3依赖注入 Spring bean的依赖注入有两种形式,通过构造方法注入和通过set方法注入。构造方法注入是通过constructor-arg元素来指定的,而set方法注入是通过property元素来指定的。

3依赖注入

Spring bean的依赖注入有两种形式,通过构造方法注入和通过set方法注入。构造方法注入是通过constructor-arg元素来指定的,而set方法注入是通过property元素来指定的。

3.1构造方法注入

先来看一个简单的示例:

	<bean id="hello" class="com.app.Hello">
		<constructor-arg value="hello"/>
	</bean>

上述配置定义了一个类型为com.app.Hellobean,我们通过constructor-arg指定了其第一个构造参数的值为字符串“hello”,这就是一个简单的通过构造方法进行注入的示例。

当参数类型为基本数据类型时可以直接通过constructor-arg元素的value属性指定对应的值,更确切的讲应该是Spring能够通过String进行转换的类型,默认Spring能将String转换成对应的基本数据类型,其它的需要自己指定转换规则了。如上面示例中的value=”hello”就是这样的。
当有多个构造参数时就需要使用多个constructor-arg进行定义,默认会将定义的顺序作为参数的顺序。

public class Hello {

	public Hello(String str1, boolean b2, int i3) {
		
	}
	
}

如上Class,我们在定义对应的bean时可以如下定义,这个时候默认会按照定义的顺序将第一个参数赋值给构造方法的第一个参数,第二个给第二个,第n个给第n个。

	<bean id="hello" class="com.app.Hello">
 		<constructor-arg value="str1"/><!-- str1 -->
 		<constructor-arg value="true"/><!-- b2 -->
 		<constructor-arg value="3"/><!-- i3 -->
 	</bean>

当然,我们也可以明确的利用index来指定constructor-arg对应参数的位置,index是从0开始的,即第一个参数对应的index为0。使用index时,Hello对应的bean可以如下定义。

	<bean id="hello" class="com.app.Hello">
 		<constructor-arg index="1" value="true"/><!-- b2 -->
 		<constructor-arg index="0" value="str1"/><!-- str1 -->
 		<constructor-arg index="2" value="3"/><!-- i3 -->
 	</bean>

当构造参数对应于ApplicationContext中的一个bean时,我们也可以通过ref属性关联对应的bean,即注入的不再是普通的字符串,而是对应的bean

public class Hello {

	public Hello(World world1) {
		
	}
	
}
	<bean id="world" class="com.app.World"/>
 
 	<bean id="hello" class="com.app.Hello">
 		<constructor-arg ref="world"/>
 	</bean>

我们还可以通过constructor-arg元素的name属性来指定对应constructor-arg对应的参数,如:

public class Hello {

	public Hello(String s1, int i2) {
		
	}
	
}
	<bean id="hello" class="com.app.Hello">
 		<constructor-arg name="i2" value="2"/><!-- 对应参数i2 -->
 		<constructor-arg name="s1" value="1"/><!-- 对应参数s1 -->
 	</bean>

但是这需要我们的class是通过debug方式进行编译的,这样Spring才能识别出对应的参数名称。当然我们也可以通过JDK提供的@ConstructorProperties注解来指定构造参数对应的名称。如:

public class Hello {

	@ConstructorProperties({"s1", "i2"})
	public Hello(String s1, int i2) {
		
	}
	
}

当我们的构造参数比较复杂,比如是一个array、list、set、map等或者需要定义一个内部的bean时,我们可以直接在constructor-arg元素中间进行定义,如:

	<bean id="hello" class="com.app.Hello">
 		<constructor-arg>
 			<bean class="com.app.World"/>
 		</constructor-arg>
 	</bean>

3.2set方法注入

set方法注入是通过property元素定义的。定义时我们需要指定property元素的name属性,其对应的值并非bean需要进行注入的属性名称,而是对应set方法去掉set前缀后首字母小写的结果。

public class Hello {

	private String prop1;
	
	public void setProp(String prop) {
		this.prop1 = prop;
	}
	
}

对于上述class定义,如果现在我们需要定义对应的bean,并通过setProp()方法将字符串“Value”注入给其私有属性prop1,那么我们的bean应该如下定义:

	<bean id="hello" class="com.app.Hello">
		<property name="prop" value="Value"/>
	</bean>

在上述示例中property元素对应的语义是setProp(“value”),即我们的注入虽然是通过property元素进行的,但其不是通过bean的某属性进行注入的,而是通过对应的set方法进行注入的。
对于基本数据类型值我们可以直接通过property元素的value属性进行注入,如果需要注入其它bean,我们可以通过在property元素下定义ref元素进行引用或者通过property元素的ref属性进行引用,也可以在property元素下定义bean元素进行注入。对于其它集合类型,如Set、List、Map、Array、Properties等则可以在property元素下通过set、list等元素进行定义。

3.3idref

当我们需要通过构造方法或者set方法给bean注入一个普通的字符串类型的值时,我们可以直接进行注入,如下就是直接将字符串“Value1”通过setP1()方法注入对应的bean的示例。

	<bean id="hello" class="com.app.Hello">
		<property name="p1" value="Value1"/>
	</bean>

当我们需要注入的普通字符串是bean容器中另一个beanbeanName时,我们还可以通过idref元素来指定对应的值,此时对应的值是通过idref元素的bean属性来指定的。当使用idref元素来指定对应的值时Spring将检查ApplicationContext中是否存在idnameidref元素的bean属性值的bean,所以当我们使用idref元素时需要我们的ApplicationContext中存在idref对应的bean。当我们需要指定的值确实是ApplicationContext中一个beanidname时,这可以帮助我们在Spring初始化对应的bean时就发现对应的错误。

	<bean id="world" class="com.app.World"/>
	<bean id="hello" class="com.app.Hello">
		<!-- 将字符串world通过bean的setP1()方法进行注入 -->
		<property name="p1">
			<!-- 注入的是字符串world,但是Spring将检查ApplicationContext中是否存在id或name为world的bean -->
			<idref bean="world"/>
		</property>
	</bean>

在上述配置中我们给idhellobean通过setP1()方法注入的是字符串world,而不是其对应的bean。由于我们是通过idref元素来注入字符串world的,Spring将检查ApplicationContext中是否存在idnameworldbean

3.4ref元素关联其它bean

不管是通过构造方法注入还是通过set方法注入依赖项,我们都可以通过ref元素关联其它的beanref元素可以用来定义对应的关联项,而真正的关联项是通过ref元素的bean属性或parent属性来指定的,它们对应的是目标beanidname

	<bean id="hello" class="com.app.Hello">
		<property name="world">
			<ref bean="world"/><!-- 关联id或name为world的bean -->
		</property>
	</bean>
	<bean id="world" class="com.app.World"/>

refbean属性关联和parent属性关联是不同的。通过bean属性指定关联时会在当前容器及其父容器中寻找关联项,而通过parent属性指定关联时只会在当前容器的父容器中寻找关联项。

	<!-- 假设是定义在父容器中的bean -->
	<bean id="parenWorld" class="com.app.World"/>
	
	<bean id="hello" class="com.app.Hello">
		<property name="world">
			<ref parent="parentWorld"/><!-- 关联父容器中id或name为world的bean -->
		</property>
	</bean>

不管是通过构造方法注入还是通过set方法注入,我们都可以通过属性ref来替代<ref bean=”…”/>,如上面的示例我们就可以替换成如下这样:

	<bean id="hello" class="com.app.Hello">
		<property name="world" ref="world"/><!-- 使用ref属性替代<ref bean="..."/> -->
	</bean>
	<bean id="world" class="com.app.World"/>

3.5复合属性的注入

设想一下我们的beanA有一个属性beanB,而beanB又有一个属性beanCbeanC又有一个属性propD,我们可以直接在定义beanA的时候指定对应的beanB的属性beanC的属性propD的值,如:

	<bean id="beanA" class="com.app.beanA">
		<property name="beanB.beanC.propD" value="ValueD"/>
	</bean>

其对应的语义是beanA.getBeanB().getBeanC().setPropD(“ValueD”),所以能够成功指定propD值的条件是getBeanB()不能为nullgetBeanB()getBeanC()也不能为null。当然,最终要注入的不一定是基本数据类型,换成是一个bean也是可以的,如:

	<bean id="beanA" class="com.app.beanA">
		<property name="beanB.beanC.beanD" ref="beanD"/>
	</bean>

(注:本文是基于Spring4.1.0所写)

目录
相关文章
|
2月前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
129 3
|
2月前
|
Java 测试技术 程序员
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring框架在日常开发中使用频繁,其依赖注入机制带来了极大的便利。然而,尽管@Autowired注解简化了依赖注入,Spring官方却不推荐在字段上使用它。本文将探讨字段注入的现状及其存在的问题,如难以进行单元测试、违反单一职责原则及易引发NPE等,并介绍为何Spring推荐构造器注入,包括增强代码可读性和维护性、方便单元测试以及避免NPE等问题。通过示例代码展示如何将字段注入重构为构造器注入,提高代码质量。
107 1
|
10天前
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
一键注入 Spring 成员变量,顺序编程
|
13天前
|
Java 数据库 数据安全/隐私保护
轻松掌握Spring依赖注入:打造你的登录验证系统
本文以轻松活泼的风格,带领读者走进Spring框架中的依赖注入和登录验证的世界。通过详细的步骤和代码示例,我们从DAO层的创建到Service层的实现,再到Spring配置文件的编写,最后通过测试类验证功能,一步步构建了一个简单的登录验证系统。文章不仅提供了实用的技术指导,还以口语化和生动的语言,让学习变得不再枯燥。
29 2
|
5月前
|
XML Java 测试技术
Spring Boot中的依赖注入和控制反转
Spring Boot中的依赖注入和控制反转
|
2月前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
69 1
|
4月前
|
XML Java 数据格式
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
这篇文章是Spring5框架的实战教程,主题是IOC容器中Bean的集合属性注入,通过XML配置方式。文章详细讲解了如何在Spring中注入数组、List、Map和Set类型的集合属性,并提供了相应的XML配置示例和Java类定义。此外,还介绍了如何在集合中注入对象类型值,以及如何使用Spring的util命名空间来实现集合的复用。最后,通过测试代码和结果展示了注入效果。
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
|
4月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
61 0
|
4月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
44 2
|
4月前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
55 0
下一篇
DataWorks