Spring5系列(四) | 依赖注入

简介: Spring5系列(四) | 依赖注入

上篇文章我们讲解了如何通过spring的工厂创建对象。对象有了,但是其实往往我们也不能够直接进行使用,有时候需要对对象进行赋值的操作。而spring中有一个比较重要的概念叫做依赖注入,什么是依赖注入的,其实就是对于成员变量的赋值。那么我们就来了解下spring如何完成依赖注入。

一. 传统方式的注入-对象赋值

我们传统的方式是如何完成赋值的呢,一般有三种方式。我们还是以User类为例

publicclassUser{
privateIntegerid;
privateStringname;
// get set 这里省略  }
  1. 直接赋值(不常用)
Useruser=newUser();
user.id=1;
user.name="张三";

这种方式不是很常见,因为根据封装的特性,一般情况下,我们的成员变量都会设置为私有,所以这种方式一般都用于本类中使用,局限性较大。所以不是很常用。

  1. set方法赋值
Useruser=newUser();
user.setId(1);
user.setName("张三");

这种方式就很常见了,就不多解释了,应该算是最常见的操作了。

  1. 构造方法赋值

要想使用构造方法赋值,前提是我们要提供对应的有参构造方法。所以User类需要改造一下:

publicclassUser{
privateIntegerid;
privateStringname;
// get set 这里省略  // 注意无参构造要显示声明出来publicUser(){}
publicUser(Integerid, Stringname){
this.id=id;
this.name=name;
  }  
}

调用有参构造方法赋值User user = new User(1, "张三");

二. spring赋值-依赖注入

spring本身也为我们提供了给对象赋值的方式,并且自己起了一个很有逼格的名字叫依赖注入。所谓依赖注入就是就是给对象的成员变量进行赋值。 那么通过spring的依赖注入有什么好处呢,其实好处就是解耦合。因为一般情况下,我们如果直接在代码里进行对象的赋值,修改起来是比较麻烦的,也就是常说的硬编码,所以一般我们经常把容易修改的值放入配置文件中,而通过spring的依赖注入方式,就可以很好地和配置文件结合,消除硬编码问题。

那么接下来我们就演示下spring的赋值方式

2.1 Set注入

顾名思义,就是通过set方法进行注入。还是以上面的User 类为例,如果使用spring赋值的方式如下:

<beanid="user"class="com.spring.User"><propertyname="id"><value>1</value></property><propertyname="name"><value>张三</value></property></bean>

通过这段配置可以看出,赋值是通过<property> 标签完成的,其中name值代表的就是成员变量的名称,嵌入<value> 标签进行赋值。 这里一定要注意,<property>标签是通过set方法完成赋值的,所以你的User类中一定更要对应的set方法,否则是无法完成赋值操作的。

我们在来说下<value> 标签,这个标签主要用于给8种基本数据类型(包括包装类) 和 String类型赋值使用的,有与类中的id和name分别是Integer和String类型,所以这里使用<value>标签进行赋值。 下面我们来介绍下如果是数组或集合类型的数据如何赋值。我们统一使用User类来举例说明。

publicclassUser{
privateIntegerid;
privateStringname;
privateint[] nums;
privateList<String>hobbyList;
privateSet<String>friendSet;
privateMap<String,String>phoneMap;
privatePropertiesprops;
// get set 这里省略  }

通过spring进行赋值:

<beanid="user"class="com.spring.User"><propertyname="id"><value>1</value></property><propertyname="name"><value>张三</value></property><propertyname="nums"><list><value>1</value><value>2</value><value>3</value></list></property><propertyname="hobbyList"><list><value>跑步</value><value>游泳</value><value>唱歌</value></list></property><propertyname="friendSet"><set><value>王五</value><value>李四</value><value>王五</value></set></property><propertyname="phoneMap"><map><entry><key><value>1</value></key><value>iphone</value></entry><entry><key><value>2</value></key><value>huawei</value></entry></map></property><propertyname="props"><props><propkey="abc">123</prop><propkey="def">456</prop></props></property></bean>

好了,上面就分别演示了如何给数组,集合,set, Map, Properties类型赋值的方式,要注意,上面凡是用<value>标签的地方都是因为里面的类型属于8中基本数据类型或String。 如果不是这样的类型就不能用<value>标签了,那么除了这9种类型外的类型应该如何赋值呢, 其实除了这九种类型之外和上述集合类型,剩下的就是我们自定义类型的赋值,这种赋值,我们要用ref的方式做引用。

publicclassUserService {
privateUserDaouserDao;
}
publicclassUserDao{
}

就比如这个案例,UserService中依赖了一个自定义的UserDao类型,这个时候我们应该如何通过spring完成注入呢,首先这是两个类,那么这两个类在注入之前肯定得先把对象创建出来,那么通过<bean> 标签即可完成。然后他们的注入关系,可以通过ref属性,指向类的id即可。

<beanid="userDao"class="com.xxx.UserDao"/><beanid="userService"class="com.xxx.UserService"><propertyname="userDao"><refbean="userDao"/></property></bean>

所以,如果上述的集合中对应的是自定义类型,就要把对应的<value>改为<ref bean="" />

除此之外其实还有一种不太常用的写法。大家了解一下即可。

<beanid = "userService"class="xx.xx.xx.UserService"><propertyname="userDao"><beanclass="xx.xx.xx.UserDao"/></property></bean>

这种写法的缺点是如果UserDao被多次引用,则会存在冗余,不利于复用。

好了接下来我们在介绍一下set注入的简化形式。

  1. 简化Value:

简化前:

<propertyname="id"><value>1</value></property>

简化后:

<propertyname="id"value=1/>

注意: 通过value属性只能简化8中基本数据类型和String

  1. 简化ref

简化前:

<propertyname="userDao"><refbean="userDao"></property>

简化后:

<propertyname="userDao"ref="userDao"></property>
  1. p:标签的形式,

但是如果想要使用这种方式,需要在xml的头上,引入p标签的命名空间配置: xmlns:p="www.springframework.org/schema/p"

jdk类型简化:

<beanid="person"class="com.xxx.Person"p:name="lisi"p:id="100"></bean>

自定义类型简化:

<beanid="userService"class="com.xxx.UserService"p:userDao-ref="userDao"></bean>

2.2 构造方法注入

讲完了set注入,我们再来说下构造方法注入,构造方法注入,顾名思义,就是spring底层通过调用Java类的构造方法完成成员变量的赋值操作。所以我们必须在类中实现类的有参构造方法才行。

@DatapublicclassCustomer {
privateStringname;
privateintage;
publicCustomer(Stringname, intage){
this.name=name;
this.age=age;
  }
}

正如上面的类,提供了两个参数的有参构造,我们该如何赋值呢:

<beanid="customer"class="com.xxx.Customer"><constructor-arg><value>James</value></constructor-arg><constructor-arg><value>11</value></constructor-arg></bean>

写个测试类测试下:

ApplicationContextctx=newClassPathXmlApplicationContext("/aplicationContext.xml");
Customerc= (Customer)ctx.getBean("customer");
System.out.println(c);// 看下对应的成员变量已经赋值成功

注意:xml文件中赋值的参数个数、顺序要和构造方法中保持一致

但是这里这个value有点问题。因为value可以用来给8种基本类型和String赋值,那如果有重载的时候改如何区分的,比如:

@DatapublicclassCustomer {
privateStringname;
privateintage;
publicCustomer(Stringname, intage){
this.name=name;
this.age=age;
  }
publicCustomer(Stringname){
this.name=name;
  }
publicCustomer(intage){
this.age=age;
  }
}

有两个只有一个参数的构造方法,而这两个值都是可以使用<value>赋值的,那我怎么区分到底调用的是哪一个呢?

<beanid="customer"class="com.xxx.Customer"><constructor-arg><value>37</value></constructor-arg></bean>

这种写法,最终37会赋值给name属性,也就是默认第一个符合的方法,那如果想赋值给age该怎么办呢? 我们可以直接指定类型赋值。

<beanid="customer"class="com.xxx.Customer"><constructor-argtype="int"><value>37</value></constructor-arg></bean>

同时在spring4.x以后,我们可以使用c标签给构造方法赋值,类似于上面的p标签,同样需要先引入c的命名空间,使用idea会自动引入。xmlns:c="www.springframework.org/schema/c"

<beanid="customer"class="com.xxx.Customer"c:name="李四"c:age="30"></bean>

三. 总结

关于spring的两种注入,我们就讲解完了,这里边更常用的是set注入,大家一定要掌握,实战中也基本都是使用set注入,因为更加灵活。构造方法局限性比较大。这里大家一定要掌握什么时候使用<value> 标签,什么时候使用<ref>. 好了今天的文章就这么多内容。

参考资料

孙帅spring详解:www.bilibili.com/video/BV185…

spring构造方法注入:  blog.csdn.net/tianzebeibe…


目录
相关文章
|
3月前
|
XML Java 测试技术
Spring Boot中的依赖注入和控制反转
Spring Boot中的依赖注入和控制反转
|
5月前
|
XML Java 程序员
Spring6框架中依赖注入的多种方式(推荐构造器注入)
依赖注入(DI)是一种过程,对象通过构造函数参数、工厂方法的参数或在对象实例构建后设置的属性来定义它们的依赖关系(即与其一起工作的其他对象)。
79 3
|
5月前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
52 0
|
2月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
37 0
|
2月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
25 2
|
2月前
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
63 0
|
3月前
|
缓存 Java Spring
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
|
4月前
|
设计模式 Java 测试技术
Spring Boot中的依赖注入详解
Spring Boot中的依赖注入详解
|
4月前
|
缓存 Java 测试技术
Spring 框架,不只是依赖注入和面向切面那么简单!
【6月更文挑战第25天】Spring框架超越DI和AOP,涵盖事务管理、数据访问抽象如`JdbcTemplate`、消息驱动支持如`@JmsListener`、缓存管理和测试工具。示例代码展示了其简化复杂性的能力,如自动事务处理、数据库操作及消息队列监听。Spring是构建高效企业级应用的全面解决方案。
32 4
|
4月前
|
Java Spring 容器
spring如何进行依赖注入,通过set方法把Dao注入到serves
spring如何进行依赖注入,通过set方法把Dao注入到serves