3 依賴注入(DI)
3 依賴注入(DI)
module:spring-04-di
概念
- 依賴注入(Dependency Injection,DI)。
- 依賴:指Bean物件的建立依賴於容器 . Bean物件的依賴資源 。
- 注入 : 指Bean物件所依賴的資源 , 由容器來設定和裝配 。
構造器注入
前文已經介紹過。
Set方法注入(重點)
要求被注入的屬性必須有set方法,set方法的方法名由set + 屬性首字母大寫,如果屬性是boolean型別 , 沒有set方法 , 是 is 。
實體類物件建立:
Address.java
package com.zzb.pojo; public class Address { private String Address; public String getAddress() { return Address; } public void setAddress(String address) { Address = address; } @Override public String toString() { return "Address{" + "Address='" + Address + '\'' + '}'; } }
Student.java
package com.zzb.pojo; import java.util.*; public class Student { private String name; private Address address; private String[] books; private List<String> hobbies; private Map<String, String> card; private Set<String> games; private String wife; private Properties info; public void setName(String name) { this.name = name; } public void setAddress(Address address) { this.address = address; } public void setBooks(String[] books) { this.books = books; } public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; } public void setCard(Map<String, String> card) { this.card = card; } public void setGames(Set<String> games) { this.games = games; } public void setWife(String wife) { this.wife = wife; } public void setInfo(Properties info) { this.info = info; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", address=" + address + ", books=" + Arrays.toString(books) + ", hobbies=" + hobbies + ", card=" + card + ", games=" + games + ", wife='" + wife + '\'' + ", info=" + info + '}'; } public String getName() { return name; } public Address getAddress() { return address; } public String[] getBooks() { return books; } public List<String> getHobbies() { return hobbies; } public Map<String, String> getCard() { return card; } public Set<String> getGames() { return games; } public String getWife() { return wife; } public Properties getInfo() { return info; } }
1、常量注入
<bean name="student" class="com.zzb.pojo.Student">
<!--普通值注入-->
<property name="name" value="Zzb"/>
</bean>
測試:
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student) context.getBean("student"); System.out.println(student.getName()); }
測試結果:
Zzb
2、Bean 注入
注意:這裡的值是一個引用,ref
<bean name="address" class="com.zzb.pojo.Address">
<property name="address" value="廈門"/>
</bean>
<bean name="student" class="com.zzb.pojo.Student">
<!--普通值注入-->
<property name="name" value="Zzb"/>
<!--引用注入-->
<property name="address" ref="address"/>
</bean>
3、陣列注入
<!--陣列注入-->
<property name="books">
<array>
<value>紅樓夢</value>
<value>三國演義</value>
<value>水滸傳</value>
<value>西遊記</value>
</array>
</property>
4、List 注入
<!--List注入-->
<property name="hobbies">
<list>
<value>打遊戲</value>
<value>聽歌</value>
<value>敲程式碼</value>
</list>
</property>
5、Map 注入
<!--Map注入-->
<property name="card">
<map>
<entry key="身份證" value="111111222222223333"/>
<entry key="校園卡" value="22222221111587"/>
</map>
</property>
6、Set 注入
<!--Set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>CS</value>
</set>
</property>
7、Null 注入
<!--Null注入-->
<property name="wife">
<null/>
</property>
8、Properties 注入
<!--Properties注入-->
<property name="info">
<props>
<prop key="性別">男</prop>
<prop key="年齡">23</prop>
</props>
</property>
測試:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
}
測試結果:
Student{name='Zzb', address=Address{Address='廈門'}, books=[紅樓夢, 三國演義, 水滸傳, 西遊記], hobbies=[打遊戲, 聽歌, 敲程式碼], card={身份證=111111222222223333, 校園卡=22222221111587}, games=[LOL, CS], wife='null', info={性別=男, 年齡=23}}
p 命名和 c 命名注入
建立 User 實體類:
注意:這裡沒有寫有參建構函式
package com.zzb.pojo;
public class User {
private int age;
private String name;
public User() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
1、p名稱空間注入:需要在標頭檔案中加入約束
匯入約束:xmlns:p="http://www.springframework.org/schema/p"
<!--p名稱空間注入,可以直接注入屬性的值:property-->
<bean name="user1" class="com.zzb.pojo.User" p:age="23" p:name="Zzb"/>
2、c名稱空間注入:需要在標頭檔案中加入約束
匯入約束:xmlns:c="http://www.springframework.org/schema/c"
<!--c名稱空間注入,通過構造器注入:constructor-arg-->
<bean name="user2" class="com.zzb.pojo.User" c:name="ZZB" c:age="23"/>
發現問題,程式報紅,因為User實體類沒有編寫有參函式構造方法。
解決辦法:把有參建構函式新增上,因此,可以得出結論,c就是所謂的構造器注入!
public User(int age, String name) {
this.age = age;
this.name = name;
System.out.println("ok");
}
測試程式碼:
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user1 = context.getBean("user1", User.class);
User user2 = context.getBean("user2", User.class);
System.out.println(user1.toString());
System.out.println(user2.toString());
}
測試結果:
ok
User{age=23, name='Zzb'}
User{age=23, name='ZZB'}
Bean 的作用域
在Spring中,那些組成應用程式的主體及由Spring IoC容器所管理的物件,被稱之為bean。簡單地講,bean就是由IoC容器初始化、裝配及管理的物件 。
幾種作用域中,request、session、globalSession作用域僅在基於web的應用中使用(不必關心你所採用的是什麼web應用框架),只能用在基於web的Spring ApplicationContext環境。
Singleton
當一個bean的作用域為Singleton,那麼Spring IoC容器中只會存在一個共享的bean例項,並且所有對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一例項。Singleton是單例型別,就是在建立起容器時就同時自動建立了一個bean的物件,不管你是否使用,他都存在了,每次獲取到的物件都是同一個物件。注意,Singleton作用域是Spring中的預設作用域,即預設作用域。要在XML中將bean定義成singleton,可以這樣配置:
<bean name="user2" class="com.zzb.pojo.User" c:name="ZZB" c:age="23" scope="singleton"/>
測試:
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user1 = context.getBean("user1", User.class);
User user2 = context.getBean("user2", User.class);
User user3 = context.getBean("user2", User.class);
System.out.println(user3 == user2);
System.out.println(user1.toString());
System.out.println(user2.toString());
}
測試結果:
ok
true
User{age=23, name='Zzb'}
User{age=23, name='ZZB'}
Prototype
當一個bean的作用域為Prototype,表示一個bean定義對應多個物件例項。Prototype作用域的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程式的方式呼叫容器的getBean()方法)時都會建立一個新的bean例項。Prototype是原型型別,它在我們建立容器的時候並沒有例項化,而是當我們獲取bean的時候才會去建立一個物件,而且我們每次獲取到的物件都不是同一個物件。根據經驗,對有狀態的bean應該使用prototype作用域,而對無狀態的bean則應該使用singleton作用域。在XML中將bean定義成prototype,可以這樣配置:
<bean name="user2" class="com.zzb.pojo.User" c:name="ZZB" c:age="23" scope="prototype"/>
或者
<bean id="user2" class="com.zzb.pojo.User" singleton="false"/>
測試:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user1 = context.getBean("user1", User.class);
User user2 = context.getBean("user2", User.class);
User user3 = context.getBean("user2", User.class);
System.out.println(user3 == user2);
System.out.println(user1.toString());
System.out.println(user2.toString());
}
測試結果:
ok
ok
false
User{age=23, name='Zzb'}
User{age=23, name='ZZB'}
Request
當一個bean的作用域為Request,表示在一次HTTP請求中,一個bean定義對應一個例項;即每個HTTP請求都會有各自的bean例項,它們依據某個bean定義建立而成。該作用域僅在基於web的Spring ApplicationContext情形下有效。考慮下面bean定義:
<bean id="loginAction" class=com.zzb.LoginAction" scope="request"/>
針對每次HTTP請求,Spring容器會根據loginAction bean的定義建立一個全新的LoginAction bean例項,且該loginAction bean例項僅在當前HTTP request內有效,因此可以根據需要放心的更改所建例項的內部狀態,而其他請求中根據loginAction bean定義建立的例項,將不會看到這些特定於某個請求的狀態變化。當處理請求結束,request作用域的bean例項將被銷燬。
Session
當一個bean的作用域為Session,表示在一個HTTP Session中,一個bean定義對應一個例項。該作用域僅在基於web的Spring ApplicationContext情形下有效。考慮下面bean定義:
<bean id="userPreferences" class="com.zzb.UserPreferences" scope="session"/>
針對某個HTTP Session,Spring容器會根據userPreferences bean定義建立一個全新的userPreferences bean例項,且該userPreferences bean僅在當前HTTP Session內有效。與request作用域一樣,可以根據需要放心的更改所建立例項的內部狀態,而別的HTTP Session中根據userPreferences建立的例項,將不會看到這些特定於某個HTTP Session的狀態變化。當HTTP Session最終被廢棄的時候,在該HTTP Session作用域內的bean也會被廢棄掉。