一
1. 創建應用對象之間協作關係的行爲通常程序裝配,這也是依賴注入的本質
2. spring裝配bean的三種機制 , 通常顯示的配置越少越好,當必須顯示配置bean的時候,推薦使用比xml更加強大的javaConfig,只有當你想使用便利的xml命名空間的時候,才應該使用xml
①:通過xml中進行顯示配置
②:在java中進行顯示的配置
③:隱式的bean發現機制和自動裝配
3. 自動化裝配bean :spring從2個角度來實現自動化裝配,組件掃描和自動裝配組合在一起,能夠將顯示配置降到最低
①組件掃描(component scanning) spring會自動發現應用上下文中所創建的bean
②:自動裝配(autowiring):spring會自動滿足bean之間的依賴
③:創建可被發現的bean示例
--接口
package package2;
public interface CompactDis {
void play();
}
--實現類
package package2;
import org.springframework.stereotype.Component;
//註明是組件類 告知spring要爲這個類創建bean
//組件掃描默認是不啓用的,所以需要顯示配製一下spring,命令它去尋找帶有@Component註解的類,併爲其創建bean
@Component
public class Sgtprppers implements CompactDis{
private String title="這是標題";
private String artist="The Beatles";
@Override
public void play() {
System.out.println(title+"==="+artist);
}
}
--java版啓動自動掃描
package package2;
import org.springframework.context.annotation.ComponentScan;
//@ComponentScan java配置啓用組件掃描的方式
//如果沒有其他配置的話,默認掃描的是與配置類相同的包及子包下帶有@Component的註解類,自動爲其創建bean
Configuration
@ComponentScan
public class CDPlayerConfig {
}
--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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="package2"/>
</beans>
--test
//使用了springJunit4ClassRunner,測試開始的時候自動創建spring應用上下文
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration 需要在哪加載配置java版本 @ContextConfiguration(classes=CDPlayerConfig.class)
//@ContextConfiguration("classpath:spring.xml") xml版本
@ContextConfiguration(classes = CDPlayerConfig.class)
public class TestCd {
@Autowired
private CompactDis compactDis;
@Test
public void test() {
Assert.notNull(compactDis);
}
}
二
- 爲組件掃面的bean命名,sping應用上下文中的所有的bean都會給一個id,當沒有明確表明的時候,sping默認會把類名首字母小寫當做id
//爲bean命名
@Component("指定的名稱")
@Named("指定的名稱")//java依賴注入規範中所提供
- 設置組件掃面的基礎包
@ComponentScan("需要掃描的包名")
//如果想要更加清晰的表明所設置的是基礎包,可以通過basePackages屬性進行配置,這裏設置的基礎包是String類型的,如果包名改變就會出現錯誤
@ComponentScan(basePackages="需要掃描的包名")
@ComponentScan(basePackages={"掃描包1","掃描包2"})
//可以通過設置包中所包含的類,這些類所所在的包將會作爲組件掃描的基礎包
@ComponentScan(basePackageClasses={配置類1.class,配置類2.class})
三
- 通過爲bean添加註解實現自動裝配
package package2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer{
private CompactDisc cd;
//當Autowired註解添加到構造方法的時候,表明當Spring創建CDPlayer bean的時候 會通過這個構造器進行實例化
// 並且會傳入一個可設置給CompactDisc類型的bean
//@Autowired 和Inject(來源Java依賴注入規範)效果類似
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play(){
cd.play();
}
//Autowired註解不進可以用在構造器上,還能用在屬性的Setter方法上
//不管是構造器、Setter方法 還是其它方法,Spring都會嘗試滿足方法參數上所聲明的依賴
//當只有一個bean匹配依賴需求的時候,這個bean會被裝配起來,沒有匹配的bean的時候會拋出異常,爲了避免異常的出現,設置屬性required=false
//當required=false 的時候 spring會嘗試自動裝配,但是沒有匹配的bean的話,spring會讓這個bean處於未裝配狀態,如果存在多個將會拋出異常 表示沒有明確指定用哪個bean裝配
@Autowired(required = false)
public void setCd(CompactDisc cd) {
this.cd = cd;
}
}
- 通過java代碼裝配bean
①:儘管在許多場景下都可以使用自動裝配,但是有的時候需要明確配置,例如 將第三方組件裝配到應用中,這時候是沒有辦法使用自動裝配的.顯示的聲明bean的時候有2中方式 java代碼和xml
②帶有@bean註解的方法可以採用任何必要的java功能來產生bean實例,構造器和set方法只是@Bean的2個簡單樣例
//@Bean會告訴spring這個方法返回一個對象,該對象要註冊爲spring應用上下文中的bean
@Bean
public CompactDis sgtPeppers(){
return new sgtPeppers();
}
//默認情況下 bean的id與帶有@Bean註解的方法名是 一樣的 可以通過name進行重新命名
@Bean(name="ss")
public CompactDis sgtPeppers(){
return new sgtPeppers();
}
//這個方法並沒有使用默認的構造器創建實例,而是調用了需要傳入對象來構造實例
//bean默認是單例的
//這種是通過方法調用
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(sgtPeppers())
}
//當做參數調用
@Bean
public CDPlayer cdPlayer(CompactDis compactDis){
return new CDPlayer(compactDis)
}
- 通過xml裝配bean
<!-- bean標籤類似於JavaConfig中@Bean註解 class是全限定的類名 -->
<bean id="sgtprppers" class="package2.Sgtprppers"/>
<!--當沒有指定id的時候 這個bean將會根據全限定名來進行命名"package2.Sgtprppers#1 有2個就是 package2.Sgtprppers#2
在基於JavaConfig的配置中我們需要直接負責創建bean的實例,在xml中默認調用構造器創建不用人爲干預
-->
<bean class="package2.Sgtprppers"/>
<!--當spring遇到這個bean元素的時候,她會創建一個CDPlayer實例
<constructor-arg ref="compactDis"/> 元素會告知spring將要一個id爲compactDis的bean引用傳遞到CDPlayer構造器中
作爲替代方案可以使用spring的C-命名空間 必須引入標題頭 xmlns:c="http://www.springframework.org/schema/c"
-->
<bean id ="cdPlayer" class="package2.CDPlayer">
<constructor-arg ref="compactDis"/>
</bean>
<!--使用c-命名空間和聲明構造參數
屬性名 c:開頭 也就是命名空間的前綴 接下來就是要裝配的構造器參數名 然後-ref 最後引用的bean id
-->
<bean id ="cd" class="package2.CDPlayer" c:cd-ref="compactDis"/>
<!--優化版
將參數嗎替換成參數的索引,防止改參數名報錯 因爲xml中不允許數字作爲屬性的第一個字符,因爲必須添加下劃線作爲前綴
當只有一個參數的時候可以 直接寫c:_-ref
-->
<bean id ="cd2" class="package2.CDPlayer" c:_0-ref="compactDis"/>
- 將字面量注入到構造器中
private String title;
private List<String> tracks;
<!--
因爲是構造參數必須要聲明它 可以傳null 當調用方法的時候就會出現空指針異常
-->
<bean id="balkDiscList" class="package2.BalkDiscList">
<constructor-arg value="xxx"/>
<constructor-arg><null/></constructor-arg>
</bean>
<!--給List賦值 預製類似我們也可以使用<ref>元素替代<value>,實現bean引用列表的裝配
<list>
<red bean="xxx1"/>
<red bean="xxx2"/>
<list>
set與list賦值區別不大 但是set會忽略重複的值,存放順序不能保證
-->
<bean id="balkDiscList1" class="package2.BalkDiscList">
<constructor-arg value="xxx"/>
<constructor-arg>
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</constructor-arg>
- 設置屬性
public class CDPlayer {
//
private CompactDis compactDis;
@Autowired
public void setCompactDis(CompactDis compactDis) {
this.compactDis = compactDis;
}
public void play(){
compactDis.play();
}
}
<!--在創建bean的時候不會報錯 但是調用方法的時候會報空指針異常 因爲沒有注入調用的那個屬性-->
<bean id="cdPlayer" class="package2.CDPlayer"/>
<!--property元素爲屬性的set方法提供與constructor-arg 元素相同的功能
此處可以使用p標籤 引入頭 xmlns:p="http://www.springframework.org/schema/p"
p標籤與c標籤類似
-->
<bean id="cdPlayer2" class="package2.CDPlayer">
<property name="compactDis" ref="compactDis"></property>
</bean>
<!--
p標籤使用規則
p:compactDis(屬性名)-ref(注入bean引用)="所注入bean的id"
-->
<bean id="cdPlayer2" class="package2.CDPlayer" p:compactDis-ref="compactDis"></bean>
- 設置屬性的字面量
public class BalkDiscList {
private String title;
private List<String> tracks;
public void setTitle(String title) {
this.title = title;
}
public void setTracks(List<String> tracks) {
this.tracks = tracks;
}
}
<!-- p標籤與c標籤一樣 沒有ref的是給字面量賦值
我們不能使用p:標籤來裝配集合 但是我們可以使用 spring util-命名空間來簡化
引入標籤頭 xmlns:util="http://www.springframework.org/schema/util"
-->
<bean id="really" class="package2.BalkDiscList">
<property name="title" value="xxx"/>
<property name="tracks">
<list>
<value>1</value>
<value>2</value>
</list>
</property>
</bean>
<!--使用util標籤-->
<util:list id="trackList">
<value>1</value>
<value>2</value>
</util:list>
<bean id="really" class="package2.BalkDiscList" p:title="xxx" p:tracks="trackList"/>
- spring util-命名空間中的元素
<util:constant> 引入某個類型的public static域,並將器暴露爲bean
<util:list> 創建一個java.util.List類型的bean,其中包含值和引用
<util:map> 創建一個java.util.Map類型的bean,其中包含值和引用
<util:properties> 創建一個java.util.properties類型的bean
<util:properties-path> 引用一個bean的屬性(或內嵌屬性),並將其暴露爲bean
<util:set> 創建一個java.util.Set類型的bean,其中包含值和引用
- 導入和混合配置
在spring應用中,儘管可能會同時使用自動化和顯示配置,即便你更喜歡通過javaConfig實現顯示配置,但是有的時候XML確是最佳的方案
關於混合配置,第一件事需要了解就是自動裝配時,它並不在意要裝配的bean來自哪裏
@Configuration
public class CDConfig {
@Bean
public CompactDis compactDis() {
return new SgtPeppers();
}
}
//compactDis()方法已經移除,我們需要將兩個類組合到一起
//一種是使用@Import註解導入 CDConfig
//或者採用一種更高級的方法 去創建一個更高級別的配置 同時引入這兩個配置類@Import({CDConfig.class,CDPlayerConfig.class})
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDis compactDis){
return new CDPlayer(compactDis);
}
}
//當一個類配置在xml中 一個是通過javaConfig配置的時候 可以類中使用註解@ImportResource("classpath:xml文件名")