Spring框架3:spring的依赖注入
Posted 别再闹了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架3:spring的依赖注入相关的知识,希望对你有一定的参考价值。
本系列笔记均是对b站教程https://www.bilibili.com/video/av47952931 的学习笔记,非本人原创
spring的依赖注入(DI)
什么是依赖注入:
作者:Angry Bugs
链接:https://www.zhihu.com/question/32108444/answer/581948457
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
看了几个高赞答案,感觉说得还是太啰嗦了。依赖注入听起来好像很复杂,但是实际上炒鸡简单,一句话说就是:本来我接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象。也就是说我对对象的『依赖』是注入进来的,而和它的构造方式解耦了。构造它这个『控制』操作也交给了第三方,也就是控制反转。不举抽象的什么造汽车或者小明玩儿手机的例子了。一个很实际的例子,比如我们要用 redis 实现一个远程列表。耦合成一坨的代码可以是这样写,其中我们需要自己构造需要用的组件:class RedisList:
def __init__(self, host, port, password):
self._client = redis.Redis(host, port, password)
def push(self, key, val):
self._client.lpush(key, val)
l = RedisList(host, port, password)依赖翻转之后是这样的:class RedisList:
def __init__(self, redis_client)
self._client = redis_client
def push(self, key, val):
self._client.lpush(key, val)
redis_client = get_redis_client(...)
l = RedisList(redis_client)看起来好像也没什么区别,但是考虑下面这些因素:线下线上环境可能不一样,get_redis_client 函数在线上可能要做不少操作来读取到对应的配置,可能并不是不是一个简单的函数。redis 这个类是一个基础组件,可能好多类都需要用到,每个类都去自己实例化吗?如果需要修改的话,每个类都要改。我们想依赖的是 redis 的 lpush 方法,而不是他的构造函数。所以把 redis 这个类的实例化由一个单一的函数来做,而其他函数只调用对应的接口是有意义的。就这么简单啊。。
构造函数注入
AccountServiceImpl :
package com.jiading.service.impl;
import com.jiading.service.IAccountService;
import java.util.Date;
/*
账户的业务层实现类
*/
public class AccountServiceImpl implements IAccountService {
//如果是经常变化的数据,并不适用于注入的方式
private String name;
private Integer age;//基本类型的包装类
private Date birthday;
public AccountServiceImpl(String name,Integer age,Date birthday){
this.name=name;
this.age=age;
this.birthday=birthday;
}
public void saveAccount() {
System.out.println("service中的saveAccount方法执行了+"+name+","+age+","+birthday);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- spring的依赖注入
依赖注入:Dependency Injection
IOC的作用:
降低程序间的耦合(依赖关系)
依赖关系的管理交给了spring来维护
依赖关系:
在当前类需要用到其他类的对象,由spring为我们提供,我们在配置文件中说明
依赖关系的维护:
称之为依赖注入
依赖注入:
能注入的数据类型:
1. 基本类型和String
2. 其他的bean类型(在配置文件中或者注解配置过的bean)
3. 复杂类型/集合类型
注入方式:
1. 使用构造函数提供
2. 使用set方法提供
3. 使用注解提供
-->
<!-- 构造函数注入:
使用标签constructor-arg
标签出现的位置:bean标签内部
标签的属性:
type:要注入的数据的数据类型,该类型也是构造函数中某个或者某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值
name:用于指定要注入的数据给构造函数中指定名称的参数赋值
以上三个用于指定给构造函数中哪个参数赋值
value:用于提供基本类型和String类型的数据
ref:用于指定其他bean类型数据,它指的就是在spring的IOC核心容器中出现过的bean对象
-->
<bean id="accountService" class="com.jiading.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="test"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<!-- 那个18会由框架自动解析为Integer类型-->
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!-- 配置一个日期对象-->
<bean id="now" class="java.util.Date"></bean>
<!-- 构造函数注入
优势:
在获取bean对象时,注入数据是必须的操作,否则对象无法实例化成功,不容易被错误调用
弊端:
改变了bean对象的实例化方式,使我们在创建对象时如果用不到这些数据,也必须提供
实际开发中,由于其不太灵活,一般不采用这种方式
-->
</beans>
set方法注入
package com.jiading.service.impl;
import com.jiading.service.IAccountService;
import java.util.Date;
/*
账户的业务层实现类
*/
public class AccountServiceImpl2 implements IAccountService {
//如果是经常变化的数据,并不适用于注入的方式
private String name;
private Integer age;//基本类型的包装类
private Date birthday;
public void saveAccount() {
System.out.println("service中的saveAccount方法执行了+"+name+","+age+","+birthday);
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
<bean id="accountService2" class="com.jiading.service.impl.AccountServiceImpl2">
<!-- set方法注入
涉及到标签:property
出现的1位置:bean内部
标签的属性:
name:用于指定注入时所调用的set方法名称(不包括set本身,只包括属性名,例如方法叫setName,这里写name就好)
value:用于提供基本类型和String类型的数据
ref:用于指定其他bean类型数据,它指的就是在spring的IOC核心容器中出现过的bean对象
优势:创建对象时没有明确的界限,可以直接使用默认构造函数
弊端:如果有某个成员必须有值,则获取对象时有可能set方法没有被执行(因为和构造函数方式相比,set方法更多的是调用者主动加property,缺少强制性
相比构造函数注入,是更常用的方式
-->
<property name="name" value="Test"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
```
##### 复杂类型的注入
```java
package com.jiading.service.impl;
import com.jiading.service.IAccountService;
import java.util.*;
/*
账户的业务层实现类
*/
public class AccountServiceImpl3 implements IAccountService {
private String[] myStrs;
private List<String> myList;
public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProps(Properties myProps) {
this.myProps = myProps;
}
private Set<String> mySet;
private Map<String, String> myMap;
private Properties myProps;
public void saveAccount() {
System.out.println(Arrays.toString(myStrs));
System.out.println(myList);
System.out.println(mySet);
System.out.println(myMap);
System.out.println(myProps);
}
}
<!-- 复杂类型的注入/集合类型的注入-->
<bean id="accountService3" class="com.jiading.service.impl.AccountServiceImpl3">
<property name="MyStrs">
<array>
<!-- 用于给List结构集合注入的标签有listarrayset。因为结构一样,所以可以互换-->
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="MyList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="MySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myMap">
<map>
<!-- 用于给map结构集合注入的标签有mapprops。因为结构一样,所以可以互换-->
<entry key="testA" value="aaa"></entry>
<entry key="testB">
<value>bbb</value>
</entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="testC">ccc</prop>
<prop key="testD">ddd</prop>
</props>
</property>
</bean>
可以看出,通过依赖注入,我们可以直接传入实例化对象,参数可以在配置文件中配置完成,省去了每次传入的麻烦
以上是关于Spring框架3:spring的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章
Spring框架学习笔记 ---[spring框架概念 , 初步上手使用Spring , 控制反转 & 依赖注入初步理解 ]