Spring(二)--------Spring配置、DI依賴注入、Bean自動裝配
5、Spring配置
5.1 别名
- 設定别名:第一種方式alias
<!--其中name為ID的對應值-->
<!--alias為賦予的别名id,可直接用alias進行調用-->
<bean id="user" class="com.zmt.pojo.User">
<constructor-arg name="name" value="zmt"/>
</bean>
<alias name="user" alias="userzzz"/>
- 第二種方式,name
<!--name值為對象屬性名-->
<bean id="user" class="com.zmt.pojo.User" name="userzm">
<constructor-arg name="name" value="zmt"/>
</bean>
</beans>
- 測試
//getBean()方法的參數,可以直接寫剛剛起的别名alias
public class MyTest {
public static void main(String[] args) {
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
//執行getBean建立對象,調用無參構造方法
User user = (User)classPathXmlApplicationContext.getBean("userzzz");
//調用對象的方法
user.show();
}
}
5.2 Bean的配置
<!-- id:bean的唯一辨別符,相當于對象名
class:bean對象所對應的全限定名:包名 + 類型
name:也是别名,相當于alias,而且name更進階,可以同時取多個别名,中間用逗号或空格或分号分隔
-->
<bean id="userT" class="com.zmt.pojo.UserT" name="user2,u2 u3">
<property name="name" value="zzz"/>
</bean>
5.3 import
- 一般用于團隊開發使用,他可以将多個配置檔案,導入合并為一個
- 假設現在項目中有多個人開發,這三個人複制不同的類開發,不同的類需要注冊在不同的bean中,我們可以利用import将所有人的beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="beans.xml"/>
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
</beans>
- 注:如果有重名的bean,預設後導入的優先使用
6、DI依賴注入
6.1 構造器注入
在前面第4部分筆記已經描述過了
6.2 set方式注入【重點】
- 依賴注入:本質是set注入
- 依賴:bean對象的建立依賴于容器
- 注入:bean對象中的所有屬性,由容器來注入
環境搭建
- 要求被注入的屬性,必須有set方法,set方法的方法名由set + 屬性首字母大寫 , 如果屬性是boolean類型 , 沒有set方法 , 是 is
- Address類
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
- Student類
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 Properties info;
private String wife;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobbies=" + hobbies +
", card=" + card +
", games=" + games +
", info=" + info +
", wife='" + wife + '\'' +
'}';
}
}
- beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.zmt.pojo.Student">
<!--第一種:普通值的注入-->
<property name="name" value="zzz"/>
</bean>
</beans>
- 測試
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student =(Student) context.getBean("student");
System.out.println(student.getName());
}
}
常量注入
<bean id="student" class="com.zmt.pojo.Student">
<!--第一種:普通值的注入-->
<property name="name" value="zzz"/>
</bean>
bean注入(pojo中屬性類型為其他pojo)
<bean id="student" class="com.zmt.pojo.Student">
<!--第二種:bean注入 ref相當于注入好的bean的值-->
<property name="address" ref="address"/>
</bean>
<bean id="address" class="com.zmt.pojo.Address">
<property name="address" value="家"/>
</bean>
數組注入
<bean id="student" class="com.zmt.pojo.Student">
<!--第三種:數組注入-->
<property name="books">
<array>
<value>月亮與六便士</value>
<value>西遊記</value>
<value>Java</value>
</array>
</property>
</bean>
List注入
<bean id="student" class="com.zmt.pojo.Student">
<!--第四種:List注入-->
<property name="hobbies">
<list>
<value>唱歌</value>
<value>舞蹈</value>
</list>
</property>
</bean>
Map注入
<bean id="student" class="com.zmt.pojo.Student">
<!--第五種:Map注入-->
<property name="card">
<map>
<entry key="身份證" value="123456123512351456"/>
<entry key="銀行卡" value="222222222222222222"/>
</map>
</property>
</bean>
Set注入
<bean id="student" class="com.zmt.pojo.Student">
<!--第六種:Set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>CSGo</value>
</set>
</property>
</bean>
Null注入
<bean id="student" class="com.zmt.pojo.Student">
<!--第七種:空值注入-->
<property name="wife">
<null/>
</property>
</bean>
Properties注入
<bean id="student" class="com.zmt.pojo.Student">
<!--第八種:properties注入-->
<property name="info">
<props>
<!--key:為鍵 兩個括号中的為值-->
<prop key="學号">2017088888</prop>
<prop key="姓别">女</prop>
</props>
</property>
</bean>
- 測試
public class MyTest {
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='zzz',
// address=Address{address='家'},
// books=[月亮與六便士, 西遊記, Java],
// hobbies=[唱歌, 舞蹈],
// card={身份證=123456123512351456,
// 銀行卡=222222222222222222},
// games=[LOL, CSGo],
// info={學号=2017088888, 姓别=女},
// wife='null'}
- 注入資訊統一
<?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="student" class="com.zmt.pojo.Student">
<!--第一種:普通值的注入-->
<property name="name" value="zzz"/>
<!--第二種:bean注入 ref相當于注入好的bean的值-->
<property name="address" ref="address"/>
<!--第三種:數組注入-->
<property name="books">
<array>
<value>月亮與六便士</value>
<value>西遊記</value>
<value>Java</value>
</array>
</property>
<!--第四種:List注入-->
<property name="hobbies">
<list>
<value>唱歌</value>
<value>舞蹈</value>
</list>
</property>
<!--第五種:Map注入-->
<property name="card">
<map>
<entry key="身份證" value="123456123512351456"/>
<entry key="銀行卡" value="222222222222222222"/>
</map>
</property>
<!--第六種:Set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>CSGo</value>
</set>
</property>
<!--第七種:空值注入-->
<property name="wife">
<null/>
</property>
<!--第八種:properties注入-->
<property name="info">
<props>
<!--key:為鍵 兩個括号中的為值-->
<prop key="學号">2017088888</prop>
<prop key="姓别">女</prop>
</props>
</property>
</bean>
<bean id="address" class="com.zmt.pojo.Address">
<property name="address" value="家"/>
</bean>
</beans>
6.3 其他方式的注入
- 兩種方式都不能直接使用,需要在xml檔案的頭檔案中導入對應限制
P命名空間注入
- 需要無參構造方法
- User實體類
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- userbeans.xml檔案
- 注意需要在頭檔案中加上限制檔案:
xmlns:p="http://www.springframework.org/schema/p"
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--P命名空間注入,可以直接注入屬性的值 p意為property-->
<bean id="user" class="com.zmt.pojo.User" p:name="zzz" p:age="18"/>
</beans>
- 測試
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user",User.class);
System.out.println(user);
}
c命名空間注入
- 需要有參構造方法
- 修改userbeans.xml檔案
- 注意需要在頭檔案中加上限制檔案:
xmlns:c="http://www.springframework.org/schema/c"
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--P命名空間注入,可以直接注入屬性的值 p意為property-->
<bean id="user" class="com.zmt.pojo.User" p:name="zzz" p:age="18"/>
<!--C命名空間注入,可以通過構造器注入,construct-->
<bean id="user2" class="com.zmt.pojo.User" c:age="20" c:name="mmm"/>
</beans>
- 測試
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user2",User.class);
System.out.println(user);
}
6.4 Bean作用域
- 在Spring中,那些組成應用程式的主體及由Spring IoC容器所管理的對象,被稱之為bean。簡單地講,bean就是由IoC容器初始化、裝配及管理的對象
Scope | Description |
---|---|
singleton(單例) | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.(預設情況下)将每個Spring IoC容器的單個bean定義定位到單個對象執行個體。 |
prototype(原型) | Scopes a single bean definition to any number of object instances.将單個bean定義作用于任意數量的對象執行個體。 |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.将單個bean定義定位到單個HTTP請求的生命周期。也就是說,每個HTTP請求都有它自己的bean執行個體,該執行個體是在單個bean定義的背面建立的。僅在支援web的Spring ApplicationContext上下文中有效。 |
session | Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.将單個bean定義作用于HTTP會話的生命周期。僅在支援web的Spring ApplicationContext上下文中有效。 |
application | Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.将單個bean定義作用于ServletContext的生命周期。僅在支援web的Spring ApplicationContext上下文中有效。 |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.将單個bean定義作用于WebSocket的生命周期。僅在支援web的Spring ApplicationContext上下文中有效。 |
單例模式
- 當一個bean的作用域為Singleton,那麼Spring IoC容器中隻會存在一個共享的bean執行個體,并且所有對bean的請求,隻要id與該bean定義相比對,則隻會傳回bean的同一執行個體。Singleton是單例類型,就是在建立起容器時就同時自動建立了一個bean的對象,不管你是否使用,他都存在了,每次擷取到的對象都是同一個對象。注意,Singleton作用域是Spring中的預設作用域。
- 單例模式也就是隻new一次對象,之後getBean的都直接擷取第一次new的對象
原型模式
- 當一個bean的作用域為Prototype,表示一個bean定義對應多個對象執行個體。Prototype作用域的bean會導緻在每次對該bean請求(将其注入到另一個bean中,或者以程式的方式調用容器的getBean()方法)時都會建立一個新的bean執行個體。Prototype是原型類型,它在我們建立容器的時候并沒有執行個體化,而是當我們擷取bean的時候才會去建立一個對象,而且我們每次擷取到的對象都不是同一個對象。根據經驗,對有狀态的bean應該使用prototype作用域,而對無狀态的bean則應該使用singleton作用域。
- 原型模式也就是在之後的getBean時重新new一個對象
其他
- 幾種作用域中,request、session、application作用域僅在基于web的應用中使用(不必關心你所采用的是什麼web應用架構),隻能用在基于web的Spring ApplicationContext環境
7、Bean的自動裝配
- 自動裝配是Spring滿足bean依賴的一種方式
- Spring會在上下文自動尋找,并自動給bean裝配屬性
Spring中有三種自動裝配的方式:
- 在xml中顯式配置
- 在java中顯式配置
- 隐式的自動裝配bean【重點】
推薦不使用自動裝配xml配置 , 而使用注解
7.1 測試
- 建立兩個寵物實體類
public class Cat {
public void shout(){
System.out.println("喵");
}
}
public class Dog {
public void shout(){
System.out.println("汪");
}
}
- 建立一個使用者實體類
public class People {
private Cat cat;
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
- 編寫beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.zmt.pojo.Cat"/>
<bean id="dog" class="com.zmt.pojo.Dog"/>
<bean id="people" class="com.zmt.pojo.People">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="name" value="張"/>
</bean>
</beans>
- 測試:輸出結果正常,環境配置完好
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
7.2 byName(按名稱自動裝配)
- autowire byName(按名稱自動裝配)
- 由于在手動配置xml過程中,常常發生字母缺漏和大小寫等錯誤,而無法對其進行檢查,使得開發效率降低。
- 采用自動裝配将避免這些錯誤,并且使配置簡單化。
- 修改beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.zmt.pojo.Cat"/>
<bean id="dog" class="com.zmt.pojo.Dog"/>
<!--byName:會自動在容器上下文中查找,和自己對象Set方法後面的值對應的bean id
例如:SetDog找dog
-->
<bean id="people" class="com.zmt.pojo.People" autowire="byName">
<property name="name" value="張"/>
</bean>
</beans>
- 再次測試依舊運作成功
- 如果将cat或dog的值改為xxxcatxxx,則會報錯(空指針異常)
- 因為byName的原則是找Set方法後面的值對應的bean id,改名字之後找不到對應的set方法,對象沒有初始化。
7.3 byType(按類型自動裝配)
- autowire byType
- 使用autowire byType首先需要保證:同一類型的對象,在spring容器中唯一。如果不唯一,會報不唯一的異常。
- 修改beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.zmt.pojo.Cat"/>
<bean id="dog" class="com.zmt.pojo.Dog"/>
<!--byType:會自動在容器上下文中查找,和自己對象屬性類型相同的bean
例如:Dog找Dog類型的bean-->
<bean id="people" class="com.zmt.pojo.People" autowire="byType">
<property name="name" value="張"/>
</bean>
</beans>
- 測試,可以正常運作輸出結果
- 注冊另一個Cat或Dog對象,而是報錯NoUniqueBeanDefinitionException;将cat的名稱改掉,正常運作。
- 因為本方法是按照類型自動裝配,bean的id不影響運作結果,但是不能同時擁有兩個相同的類型,會報錯
小結
- byName:需要保證所有的beanid唯一,且這個bean需要和自動注入的屬性的set方法的值一緻
- byType:需要保證所有的bean的類型唯一,且這個bean需要和自動注入的屬性類型一緻
7.4 使用注解實作自動裝配
- jdk1.5開始支援注解,spring2.5開始全面支援注解
使用注解須知:
- 導入限制:
xmlns:context="http://www.springframework.org/schema/context"
- 配置注解的支援:
<context:annotation-config/>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
- 直接在屬性上使用即可,是按照類型自動裝配的,不支援id比對
- 不需要編寫set方法,前提是這個自動裝配的屬性在IOC容器中存在,且優先(byType),如果有多個相同類型則(byName)
- 科普:@Nullable:字段标記了這個注解,說明這個字段可以為null
- 如果顯式定義了Autowired的required屬性為false,說明這個對象可以為null,否則不允許為空:
@Autowired(required = false)
- 測試
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
- 修改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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="cat" class="com.zmt.pojo.Cat"/>
<bean id="dog" class="com.zmt.pojo.Dog"/>
<bean id="people" class="com.zmt.pojo.People"/>
</beans>
- 測試,運作成功
@Qualifier
- 如果自動裝配環境比較複雜,自動裝配無法通過一個注解完成的時候,我們可以使用@Qualifier(value=“xxx”),去配置@Autowired的使用,指定唯一一個bean對象注入,@Qualifier不能單獨使用
- 測試,修改xml檔案
<bean id="dog111" class="com.zmt.pojo.Dog"/>
<bean id="dog222" class="com.zmt.pojo.Dog"/>
<bean id="cat111" class="com.zmt.pojo.Cat"/>
<bean id="cat222" class="com.zmt.pojo.Cat"/>
- 沒有添加@Qualifier注解時,直接報錯
- 添加注解
@Autowired
@Qualifier(value = "cat222")
private Cat cat;
@Autowired
@Qualifier(value = "dog222")
private Dog dog;
- 測試,運作成功
@Resource
- 如果有指定的name屬性,優先進行(byName)方式查找裝配,其次按照預設的byName方式進行裝配,如果以上都不成功,則按照(byType)方式進行裝配,都不成功,報異常
- pojo
public class People {
@Resource(name = "cat222")
private Cat cat;
@Resource
private Dog dog;
private String name;
}
- 修改beans.xml檔案
<bean id="dog" class="com.zmt.pojo.Dog"/>
<bean id="cat1" class="com.zmt.pojo.Cat"/>
<bean id="cat222" class="com.zmt.pojo.Cat"/>
<bean id="people" class="com.zmt.pojo.People"/>
- 測試,運作成功
- 修改beans.xml檔案
<bean id="dog" class="com.zmt.pojo.Dog"/>
<bean id="cat222" class="com.zmt.pojo.Cat"/>
- pojo
@Resource
private Cat cat;
@Resource
private Dog dog;
- 測試,運作成功
@Autowired與@Resource異同
相同點:
- 用注解方式注入對象,但執行順序不同
- @Autowired與@Resource都可以用來裝配bean。都可以寫在字段上,或寫在set方法上
不同點:
- @Autowired先byType,然後byName;@Resource先byName,然後byType。如果兩種情況都找不到就報錯
- @Autowired預設按類型裝配(屬于spring規範),預設情況下必須要求依賴對象必須存在,如果要允許null 值,可以設定它的required屬性為false,如:@Autowired(required=false) ,如果我們想使用名稱裝配可以結合@Qualifier注解進行使用
- @Resource(屬于J2EE複返),預設按照名稱進行裝配,名稱可以通過name屬性進行指定。如果沒有指定name屬性,當注解寫在字段上時,預設取字段名進行按照名稱查找,如果注解寫在setter方法上預設取屬性名進行裝配。當找不到與名稱比對的bean時才按照類型進行裝配。但是需要注意的是,如果name屬性一旦指定,就隻會按照名稱進行裝配。