Spring IOC Bean裝配 --day07
Spring IOC Bean裝配 --day07
碰到的問題,以及思考解決不在這裡寫,本人日記:記錄覺得需要記得常用描述,具體實現相關知識點。寫日記是為了梳理知識點加深記憶。可能缺少很多資訊,如果您看到給您道個歉
一、概述
IOC 控制反轉:傳統開發中,通過new來實現手動建立物件,IOC思想則是通過第三方來獲取物件,不管物件怎麼來的,你需要就跟他(Spring)說就行了,實現原理也是基於反射。
IOC 容器:
Spring 提供 IoC 容器來管理和容納我們所開發的各種各樣的 Bean,並且我們可以從中獲取各種釋出在 Spring IoC 容器裡的 Bean,並且通過描述可以得到它。
Spring 容器設計
盜圖:
1)BeanFactory: Spring IoC 容器所定義的最底層介面(getBean方法引數:Bean.class、“beanName”、“beanName”,Bean.class)。
2)ApplicationContext:Spring IoC 容器所定義最高階介面之一,使用最廣泛的介面,功能強大,支援方法較多。
二、簡單實現
匯入相關包(過)Maven管理
pojo類
public class Clothes {
public Clothes()
{
System.out. println("一件衣服被建立了"+System.identityHashCode(this));
}
private String color;
private int size;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public void destory(){
//System.identityHashCode(Object)方法可以返回物件的記憶體地址
System.out.println("這件衣服被銷燬了"+System.identityHashCode(this));
}
}
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 class="my.test.Clothes" id="clothes" lazy-init="true" destroy-method="destory" >
<property name="color" value="red"/>
<property name="size" value="33"/>
</bean>
</beans>
測試類
//初始化容器
ApplicationContext applicationContext =new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
//getBean方法拿到物件
Clothes clothes1 = (Clothes)applicationContext.getBean("clothes");
//列印結果資訊
System.out.println(clothes1.getColor()+clothes1.getSize());
結果
一件衣服被建立了1740846921
衣服顏色:red衣服尺碼:33
三、Bean的裝配
根據優先順序排序 順序3→2→1,但由於種種因素的限制有些裝配無法實現,只能採用次一級優先順序方法來實現裝配。
1.xml檔案中顯示配置(二中配置)
簡單易懂,當使用第三方類的時候,有些類並不是我們開發的,我們無法修改裡面的程式碼只能使用xml進行配置。
<bean id="唯一標識,並不是必須 可以使用name代替 沒有定義預設是全限定名#(0++)按定義次數遞加" class="類的全限定名">
<!--設值注入簡單型別-->
<property name="屬性名" value="屬性值" />
<!--屬性也是一個Bean 通過refy引用-->
<property name="屬性名" ref="另一個Bean的id或者name"/>
<property name="屬性名" >
<ref bean="另一個Bean的id或者name"/>
</property>
<property name="屬性名">
<value>另一種值寫入方式</value>
<!--除了value 還可以 是Set、Map、List、Array、Properties 等-->
<!--和各自子節點的對應關係
list\Set\Array:value
Map:entry
Properties :property(必填key屬性)
-->
</property>
</bean>
名稱空間裝配
c-名稱空間:用於構造注入簡化寫法:
<!--未引入名稱空間-->
<bean....>
<constructor-arg name="id" value="1" />
<constructor-arg name="name" value="學生1"/>
</bean>
<!-- 引入c- 名稱空間後-->
<bean name="student2" class="pojo.Student"
c:id="2" c:name="學生2"/>
<!--如果需要設定引用的話在對應引數名後加上 (-ref) 比如:c:name-ref="beanId"
也可以用下標代替屬性名
如:c:_0=""、c:_1=""
-->
p-名稱空間:簡化設定注入寫法,寫法和c-名稱空間簡寫規則一樣c換成p
util-名稱空間:簡化集合類元素
<!-- 引入util-名稱空間之前 -->
<property name="list">
<list>
<ref bean="bean1"/>
<ref bean="bean2"/>
</list>
</property>
<!-- 引入util-名稱空間之後 -->
<util:list id="list">
<ref bean="bean1"/>
<ref bean="bean2"/>
</util:list>
元素 | 描述 |
---|---|
<util:constant> | 引用某個型別的 public static 域,並將其暴露為 bean |
<util:list> | 建立一個 java.util.List 型別的 bean,其中包含值或引用 |
<util:map> | 建立一個 java.util.map 型別的 bean,其中包含值或引用 |
<util:properties> | 建立一個 java.util.Properties 型別的 bean |
<util:property-path> | 引用一個 bean 的屬性(或內嵌屬性),並將其暴露為 bean |
<util:set> | 建立一個 java.util.Set 型別的 bean,其中包含值或引用 |
通常一個配置檔案寫大量Bean配置資訊會變得十分臃腫,可以通過import引入其他配置檔案
寫法:
<import resource="bean.xml" />
2.java類和介面中配置
可以減少xml檔案中複雜的手動配置,可以實現自動裝配。
兩種使IOC容器能發現Bean的方法:
1)包掃描
定義掃描的包資源,讓Spring IOC去掃描相應的包,將對應Bean裝配進來
2)自動裝配
通過註解定義,使得一些依賴關係可以通過註解完成。
@Component、@Value、@ComponentScan
簡單規則:
@Component(value=“Bean的id,如果不寫預設類名”)
@value(“下面屬性的注入值”)
@ComponentScan:掃描當前包路徑下的所有被@Compoent註解標記的pojo類。
示例程式碼:
//測試pojo類
package my.test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component(value="clothes")
public class Clothes {
public Clothes()
{
System.out.println("一件衣服被建立了"+System.identityHashCode(this));
}
@Value("red")
private String color;
@Value("31")
private int size;
//getter setter and others
}
//測試類
@ComponentScan
public class SpringTest {
public static void main(String args[])
{
//初始化容器
//ApplicationContext applicationContext =new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Clothes.class);
//getBean方法拿到物件
Clothes clothes1 = (Clothes)applicationContext.getBean("clothes",Clothes.class);
//列印結果資訊
System.out.println("衣服顏色:"+clothes1.getColor()+"衣服尺碼:"+clothes1.getSize());
}
}
實驗成功
@Value(只能注入簡單型別值,不能注入物件)、@ComponentScan(只能掃描當前包)
@ComponentScan配置項:
basePackages:Spring 根據它配置的資訊去掃描對應的包以及子包,裝配配置好的Bean
basePackageClasses:他會根據設定的類去自動查詢到類所在的包,將配置好的Bean裝配進來。
@ComponentScan(basePackages = "my.test")
@ComponentScan(basePackageClasses = my.test.Clothes.class)
注意:basePackages 和 basePackageClasses 選擇
basePackages較簡單且易讀,因為設定過程中使用字串傳遞引數,寫入錯誤不會提示,在大量重構的專案中,經常需要修改報名 不適合使用。basePackageClasses 中包名變化,原來寫入資訊和當前包名不符合,或類名不符 IDE中會報錯
@Autowired
通過它可以實現物件自動裝配,用它標記一個自定義型別屬性,等到Spring IOC 容器已經定位好所有Bean的時候,按照這個屬性的自定義型別,去查詢Bean,對這個屬性實現裝配
建立一個公司型別,讓衣服類擁有一個公司屬性,並用@Autowired
程式碼:
//公司
@Component(value="company")
public class Company {
@Value("小公司")
private String companyName;
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
}
//衣服加入對公司所在包的掃描、或掃描公司類
@Autowired
private Company company;
//getter、setter..
測試成功。
注意:
@Autowired預設能找到相應的Bean注入,如果注入失敗會報錯。解決方法:設定@Autowired(required = false) 設定注入失敗不會報錯。
註解不僅僅能配置在屬性之上,還允許方法配置/
當發現多個相同型別的Bean 無法確定注入哪一個Bean:@Primary 標記一個類,這個類滿足條件會被優先注入,@Qualifier指定注入的Bean的id
3.隱式Bean發現自動裝配
@Bean
上面通過@Component來裝配Bean,該註解使用在類上,引用第三方包的時候很不方便,&Bean可以用到到第三方包的方法上。
測試程式碼:
@Configuration//註解相當於 XML 檔案的根元素,必須要,有了才能解析其中的 @Bean
public class BeanTest {
@Bean(name = "testName")
public String test()
{
System.out.println("測試Bean方法");
return "必須有返回值";
}
}
//測試類
// 在 pojo 包下掃描
ApplicationContext context = new AnnotationConfigApplicationContext("my.test");
context.getBean("testName");
((AnnotationConfigApplicationContext) context).close();
//測試成功
@Bean只用於方法,方法必須有返回值否則報錯
Bean配置項
屬性 | 作用 |
---|---|
name: | 是一個字串陣列,允許配置多個 BeanName |
autowire: | 標誌是否是一個引用的 Bean 物件,預設值是 Autowire.NO |
initMethod: | 自定義初始化方法 |
destroyMethod: | 自定義銷燬方法 |