3、Spring的DI依賴注入
一、DI介紹
1、DI介紹
- 依賴注入,應用程式執行依賴的資源由Spring為其提供,資源進入應用程式的方式稱為注入。
- Spring容器管理容器中Bean之間的依賴關係,Spring使用一種被稱為“依賴注入”的方式來管理Bean之間的依賴關係。
- 使用依賴注入,不僅可以為Bean注入普通的屬性值,還可以注入其他Bean的引用。依賴注入是一種優秀的解耦方式,其可以讓Bean以配置檔案組織在一起,而不是以硬編碼的方式耦合在一起。
2、依賴注入
依賴注入: Dependency Injection。它是 spring 框架核心 ioc 的具體實現。
3、為什要依賴注入
直接用物件,不需要去new物件。所謂的注入就是建立物件的過程而已。
-
傳統的程式碼,每個物件負責管理與自己需要依賴的物件,導致如果需要切換依賴物件的實現類時,需要修改多處地方。同時,過度耦合也使得物件難以進行單元測試。
-
依賴注入把物件的創造交給外部去管理,很好的解決了程式碼緊耦合(tight couple)的問題,是一種讓程式碼實現鬆耦合(loose couple)的機制。
-
例如:我們控制層呼叫業務層需要在控制層建立業務層的物件,之前我們需要Person p = new Person;現在不需要我們自己去new person,直接交給spring去建立,我可以直接拿過來用。
Spring 支援的注入方式共有四種: set 注入、構造器注入、靜態工廠注入、例項化工廠注入。
4、IOC與DI之間的關係
IoC(Inversion of Control 控制反轉):是一種面向物件程式設計中的一種設計原則,用來減低計算機程式碼之間的耦合度。其基本思想是:藉助於“第三方”實現具有依賴關係的物件之間的解耦。
DI(Dependence Injection 依賴注入):將例項變數傳入到一個物件中去(Dependency injection means giving an object its instance variables)。
- 控制反轉是一種思想
- 依賴注入是一種設計模式
- IoC框架使用依賴注入作為實現控制反轉的方式
說人話:就是DI與IOC相輔相成,相互包含。不能說成DI就是IOC,這兩個本質區別是:IOC是思想,DI設計模式。
二、Spring的依賴注入方式
1、Set注入
1、set注入介紹
思考:呼叫某個類的方法,你是怎麼操作的?
答:我通過該類的構造器建立物件,通過物件去呼叫方法。
看圖說話:
方式一與方式二對比:
- 方式二沒有主動的去例項物件,而是通過帶引數的方法傳遞過來UserDao物件,從而實現UserService對UserDao的依賴.
實際上建立物件是交給Spring容器來建立的
- 屬性欄位需要提供set方法。並且還需要通過修改spring的配置檔案,進行相關的注入資訊配置。
2、Set注入標籤介紹
名稱:property
型別:標籤
歸屬:bean標籤
作用:使用set方法的形式為bean提供資源
格式:
<bean>
<property />
</bean>
基本屬性:
<property name="propertyName" value="propertyValue" ref="beanId"/>
name:對應bean中的屬性名,要求該屬性必須提供可訪問的set方法(嚴格規範為此名稱是set方法對應名稱)
value:設定非引用型別屬性對應的值,不能與ref同時使用
ref:設定引用型別屬性對應bean的id ,不能與value同時使用
注意:一個bean可以有多個property標籤,屬性欄位需要提供set方法
3、測試Set注入方式建立物件
- 在UserServiceImpl建立UserDao的變數,並在UserServiceImpl變數提供Set方法。
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
@Override
public void saveUser() {
System.out.println("service層通過注入的方式呼叫dao層,成功啦!");
userDao.saveUser();
}
- 介面類UserService
public interface UserService {
void saveUser();
}
- dao層方法
public class UserDao {
public void saveUser(){
System.out.println("我是dao層");
}
}
4.配置檔案配置
<?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">
<bean id="userService" class="com.why.service.impl.UserServiceImpl">
<!--
<property/> 中的name對應set方法的set後面的名字且首字母小寫
ref 代表注入的是引用型別,所以需要填入藥注入bean的id
說明:service引用到層,相當於在service裡面建立userDao的物件,直接被service引用,與new物件呼叫方法類似
-->
<property name="userDao" ref="userDao"/>
</bean>
<!--將注入的資源宣告為bean,交由spring管理-->
<bean id="userDao" class="com.why.dao.UserDao"/>
</beans>
- 測試類
public class UserController {
public static void main(String[] args) {
//獲取Spring上下文環境 (載入配置檔案)
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
/*
通過getBean方法得到Spring容器中例項化好的Bean物件 (例項化Bean物件)
userService代表的是配置檔案中bean標籤的id屬性值(id標識唯一的bean)
*/
UserService userService = (UserService) context.getBean("userService");
userService.saveUser();
}
}
6.測試結果
程式沒有報錯,並正確輸出我們要列印的東西
2、構造方法注入
1、構造器注入標籤介紹
名稱:constructor-arg
型別:標籤
歸屬:bean標籤
作用:使用構造方法的形式為bean提供資源,相容早期遺留系統的升級工作
格式:
<bean>
<constructor-arg />
</bean>
基本屬性:
<constructor-arg name="argsName" value="argsValue />
name:對應bean中的構造方法所攜帶的引數名
value:設定非引用型別構造方法引數對應的值,不能與ref同時使用
其他屬性:
<constructor-arg index="arg-index" type="arg-type" ref="beanId"/>
ref:設定引用型別構造方法引數對應bean的id ,不能與value同時使用
type :設定構造方法引數的型別,用於按型別匹配引數或進行型別校驗
index :設定構造方法引數的位置,用於按位置匹配引數,引數index值從0開始計數
注意:一個bean可以有多個constructor-arg標籤
2、構造注入測試案例
- 在UserServiceImpl建立UserDao的變數,並在UserServiceImpl變數提供構造方法。
public class UserServiceImpl implements UserService {
private UserDao userDao;
private String name;
private int age;
//根據構造器進行注入
public UserServiceImpl(UserDao userDao, String name, int age) {
this.userDao = userDao;
this.name = name;
this.age = age;
}
@Override
public void saveUser() {
System.out.println("name="+name);
System.out.println("age="+age);
userDao.saveUser();
}
public void destroy(){
System.out.println("bean銷燬");
}
}
- 修改配置檔案
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
構造器注入
-->
<bean id="userService" class="com.why.service.impl.UserServiceImpl">
<!--
對構造器進行賦值
-->
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="age" value="22"></constructor-arg>
<constructor-arg name="name" value="laity"/>
</bean>
<bean id="userDao" class="com.why.dao.UserDao"></bean>
</beans>
3. 其它程式碼與set注入程式碼相同
- 測試結果
- 構造標籤的屬性
//根據構造器進行注入
public UserServiceImpl(UserDao userDao, String name, int age) {
this.userDao = userDao;
this.name = name;
this.age = age;
}
帶name屬性
<bean id="userService" class="com.why.service.impl.UserServiceImpl">
<!--
對構造器進行賦值
-->
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="age" value="22"></constructor-arg>
<constructor-arg name="name" value="laity"/>
</bean>
不帶name屬性,順序要按照構造方法的引數型別進行設定
<bean id="userService" class="com.why.service.impl.UserServiceImpl">
<!--
對構造器進行賦值
-->
<constructor-arg ref="userDao"></constructor-arg>
<constructor-arg value="22"></constructor-arg>
<constructor-arg value="laity"/>
</bean>
index0表示第一個引數,index1表示第二個引數,以此類推
<bean id="userService" class="com.why.service.impl.UserServiceImpl">
<!--
對構造器進行賦值
-->
<constructor-arg index ="0" ref="userDao"></constructor-arg>
<constructor-arg index ="1" value="22"></constructor-arg>
<constructor-arg index ="2" value="laity"/>
</bean>
3、集合注入
1、集合型別標籤介紹
名稱:array,list,set,map,props
型別:標籤
歸屬:property標籤 或 constructor-arg標籤
作用:注入集合資料型別屬性
格式:
<property>
<list></list>
</property>
1、集合型別資料注入——list(重點)
<property name="xxx">
<list>
<value>why</value>
<value>66666</value>
</list>
</property>
(2)集合型別資料注入——props(重點)
<property name="xxx">
<props>
<prop key="name">javaxxf</prop>
<prop key="value">666666</prop>
</props>
</property>
(3)集合型別資料注入——array (瞭解)
<property name="xxx">
<array>
<value>123456</value>
<value>66666</value>
</array>
</property>
(4)集合型別資料注入——set(瞭解)
<property name="xxx">
<set>
<value>javaxxf</value>
<value>66666</value>
</set>
</property>
(5)集合型別資料注入——map(瞭解)
<property name="xxx">
<map>
<entry key="name" value="javaxf66666"/>
<entry key="value" value="66666"/>
</map>
</property><property name="xxx">
<map>
<entry key="name" value="javaxf66666"/>
<entry key="value" value="66666"/>
</map>
</property>
2、測試集合注入
- 建立集合並提供set方法
package com.why.service.impl;
import com.why.service.UserService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
public class UserServiceImpl implements UserService {
private ArrayList arrayList;
private Properties properties;
private int[] arr;
private HashSet hset;
private HashMap hmap;
public void setArrayList(ArrayList arrayList) {
this.arrayList = arrayList;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setArr(int[] arr) {
this.arr = arr;
}
public void setHset(HashSet hset) {
this.hset = hset;
}
public void setHmap(HashMap hmap) {
this.hmap = hmap;
}
@Override
public void saveUser() {
System.out.println("ArrayList"+arrayList);
System.out.println("Properties"+properties);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("HashSet"+hset);
System.out.println("HashMap"+hmap);
}
}
- 配置檔案
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.why.service.impl.UserServiceImpl">
<!--list集合配置-->
<property name="arrayList">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<!--properties配置-->
<property name="properties">
<props>
<prop key="properties1">java</prop>
<prop key="properties2">java</prop>
<prop key="properties3">java</prop>
</props>
</property>
<!--陣列配置-->
<property name="arr">
<array>
<value>11</value>
<value>12</value>
<value>13</value>
</array>
</property>
<!--hashmap集合配置-->
<property name="hmap">
<map>
<entry key="map1" value="Laity1"></entry>
<entry key="map2" value="Laity2"></entry>
</map>
</property>
<!--hashset集合配置-->
<property name="hset">
<set>
<value>hset1</value>
<value>hset2</value>
<value>hset3</value>
</set>
</property>
</bean>
</beans>
- 執行結果