首先來介紹下Spring中有哪些注入方式?
我們先來思考
向一個類中傳遞資料的方式有幾種?
普通方法(set方法)
構造方法
依賴注入描述了在容器中建立bean與bean之間的依賴關係的過程,如果bean執行需要的是數位或字串呢?
參照型別
簡單型別(基本資料型別與String)
Spring就是基於上面這些知識點,為我們提供了兩種注入方式,分別是:
setter注入
簡單型別
參照型別
構造器注入
簡單型別
參照型別
依賴注入的方式已經介紹完,接下來挨個看下:
對於setter方式注入參照型別的方式之前已經介紹過,簡單看下:
在bean中定義參照型別屬性,並提供可存取的set方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
設定中使用property標籤ref屬性注入參照型別物件
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="com.itheima.dao.imipl.BookDaoImpl"/>
環境準備:
建立一個Maven專案
pom.xml新增依賴
resources下新增spring的組態檔
最終專案的結構如下:
(1)專案中新增BookDao、BookDaoImpl、UserDao、UserDaoImpl、BookService和BookServiceImpl類
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
(2)resources下提供spring的組態檔
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
(3)編寫AppForDISet執行類,載入Spring的IOC容器,並從中獲取對應的bean物件
public class AppForDISet {
public static void main( String[] args ) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
需求:在bookServiceImpl物件中注入userDao
1.在BookServiceImpl中宣告userDao屬性
2.為userDao屬性提供setter方法
3.在組態檔中使用property標籤注入
在BookServiceImpl中宣告userDao屬性,並提供setter方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
在applicationContext.xml組態檔中使用property標籤注入
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
執行AppForDISet類,檢視結果,說明userDao已經成功注入。
需求:給BookDaoImpl注入一些簡單資料型別的資料
參考參照資料型別的注入,我們可以推出具體的步驟為:
1.在BookDaoImpl類中宣告對應的簡單資料型別的屬性
2.為這些屬性提供對應的setter方法
3.在applicationContext.xml中設定
思考:
參照型別使用的是<property name="" ref=""/>
,簡單資料型別還是使用ref麼?
ref是指向Spring的IOC容器中的另一個bean物件的,對於簡單資料型別,沒有對應的bean物件,該如何設定?
在BookDaoImpl類中宣告對應的簡單資料型別的屬性,並提供對應的setter方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}
在applicationContext.xml組態檔中使用property標籤注入
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="10"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
說明:
value:後面跟的是簡單資料型別,對於引數型別,Spring在注入的時候會自動轉換,但是不能寫成
<property name="connectionNum" value="abc"/>
這樣的話,spring在將abc
轉換成int型別的時候就會報錯。
執行AppForDISet類,檢視結果,說明userDao已經成功注入。
注意:兩個property注入標籤的順序可以任意。
對於setter注入方式的基本使用就已經介紹完了,
對於參照資料型別使用的是<property name="" ref=""/>
對於簡單資料型別使用的是<property name="" value=""/>
構造器注入也就是構造方法注入,還是先準備下環境:
建立一個Maven專案
pom.xml新增依賴
resources下新增spring的組態檔
這些步驟和前面的都一致,大家可以快速的拷貝即可,最終專案的結構如下:
(1)專案中新增BookDao、BookDaoImpl、UserDao、UserDaoImpl、BookService和BookServiceImpl類
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public void save() {
System.out.println("book dao save ...");
}
}
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
(2)resources下提供spring的組態檔
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
(3)編寫AppForDIConstructor執行類,載入Spring的IOC容器,並從中獲取對應的bean物件
public class AppForDIConstructor {
public static void main( String[] args ) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
接下來,在上面這個環境中來完成構造器注入:
需求:將BookServiceImpl類中的bookDao修改成使用構造器的方式注入。
1.將bookDao的setter方法刪除掉
2.新增帶有bookDao引數的構造方法
3.在applicationContext.xml中設定
在BookServiceImpl類中將bookDao的setter方法刪除掉,並新增帶有bookDao引數的構造方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
在applicationContext.xml中設定
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
</beans>
說明:
標籤<constructor-arg>中
name屬性對應的值為建構函式中方法形參的引數名,必須要保持一致。
ref屬性指向的是spring的IOC容器中其他bean物件。
執行AppForDIConstructor類,檢視結果,說明bookDao已經成功注入。
需求:在BookServiceImpl使用建構函式注入多個參照資料型別,比如userDao
1.宣告userDao屬性
2.生成一個帶有bookDao和userDao引數的建構函式
3.在applicationContext.xml中設定注入
在BookServiceImpl宣告userDao並提供多個引數的建構函式
public class BookServiceImpl implements BookService{
private BookDao bookDao;
private UserDao userDao;
public BookServiceImpl(BookDao bookDao,UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
userDao.save();
}
}
在applicationContext.xml中設定注入
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
</beans>
說明:這兩個<contructor-arg>
的設定順序可以任意
執行AppForDIConstructor類,檢視結果,說明userDao已經成功注入。
需求:在BookDaoImpl中,使用建構函式注入databaseName和connectionNum兩個引數。
參考參照資料型別的注入,我們可以推出具體的步驟為:
1.提供一個包含這兩個引數的構造方法
2.在applicationContext.xml中進行注入設定
修改BookDaoImpl類,新增構造方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public BookDaoImpl(String databaseName, int connectionNum) {
this.databaseName = databaseName;
this.connectionNum = connectionNum;
}
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}
在applicationContext.xml中進行注入設定
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg name="databaseName" value="mysql"/>
<constructor-arg name="connectionNum" value="666"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
</beans>
說明:這兩個<contructor-arg>
的設定順序可以任意
執行AppForDIConstructor類,檢視結果
上面已經完成了建構函式注入的基本使用,但是會存在一些問題:
當建構函式中方法的引數名發生變化後,組態檔中的name屬性也需要跟著變,因為是形參的名字。
這兩塊存在緊耦合,具體該如何解決?
在解決這個問題之前,需要提前說明的是,這個引數名發生變化的情況並不多,所以上面的還是比較主流的設定方式,下面介紹的,大家都以瞭解為主。
方式一:刪除name屬性,新增type屬性,按照型別注入
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean>
這種方式可以解決建構函式形參名發生變化帶來的耦合問題
但是如果構造方法引數中有型別相同的引數,這種方式就不太好實現了
方式二:刪除type屬性,新增index屬性,按照索引下標註入,下標從0開始
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg index="1" value="100"/>
<constructor-arg index="0" value="mysql"/>
</bean>
這種方式可以解決引數型別重複問題
但是如果構造方法引數順序發生變化後,這種方式又帶來了耦合問題
介紹完兩種引數的注入方式,具體我們該如何選擇呢?
強制依賴使用構造器進行,使用setter注入有概率不進行注入導致null物件出現
強制依賴指物件在建立的過程中必須要注入指定的引數
可選依賴使用setter注入進行,靈活性強
可選依賴指物件在建立過程中注入的引數可有可無
Spring框架倡導使用構造器,第三方框架內部大多數採用構造器注入的形式進行資料初始化,相對嚴謹
如果有必要可以兩者同時使用,使用構造器注入完成強制依賴的注入,使用setter注入完成可選依賴的注入
實際開發過程中還要根據實際情況分析,如果受控物件沒有提供setter方法就必須使用構造器注入
自己開發的模組推薦使用setter注入
這裡主要講的是Spring的依賴注入的實現方式:
setter注入
簡單資料型別
<bean ...>
<property name="" value=""/>
</bean>
參照資料型別
<bean ...>
<property name="" ref=""/>
</bean>
構造器注入
簡單資料型別
<bean ...>
<constructor-arg name="" index="" type="" value=""/>
</bean>
參照資料型別
<bean ...>
<constructor-arg name="" index="" type="" ref=""/>
</bean>
依賴注入的方式選擇上
建議使用setter注入
第三方技術根據情況選擇
本文來自部落格園,作者:|舊市拾荒|,轉載請註明原文連結:https://www.cnblogs.com/xiaoyh/p/16311038.html