自動化裝配Bean
一、Spring裝配-自動化裝配
@Component和@ComponentScan
通過spring註解(@Component)來表明該類會作為組件類,並告知Spring要為這類創建bean,不過組件掃描默認是不啟動的,需要顯式的配置Spring,從而命令Spring去尋找帶有(@Component)註解的類,並為其創建bean。
1、定義接口
package com.seven.springTest.service;
public interface HelloWorldApi {
public void sayHello();
}
2、定義接口的實現類
package com.seven.springTest.service.impl;
import org.springframework.stereotype.Component;
import com.seven.springTest.service.HelloWorldApi;
@Component //通過註解指定該類組件類,告知spring要為它創建Bean
public class PersonHelloWorld implements HelloWorldApi {
@Override
public void sayHello() {
System.out.println("Hello World,This Is Person!");
}
}
3、前面說過了,spring並不能自動啟用組件掃描,需要進行顯式的配置,這裏通過java類來進行顯式的配置,定義java配置類HelloWorldConfig,在配置類中我們沒有顯式的聲明任何bean,只不過是使用了@CompontentScan註解來啟用組件掃描
package com.seven.springTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan // 啟用組件掃描
public class HelloWorldConfig {
}
現在所有的工作已經完成,我們來測試下
package com.seven.springTest.main;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.seven.springTest.HelloWorldConfig;
import com.seven.springTest.service.HelloWorldApi;
public class HelloWorldTest {
public static void main(String[] args) {
//1. 聲明Spring上下文,采用java配置類
ApplicationContext ac = new AnnotationConfigApplicationContext(HelloWorldConfig.class);
//2. 聲明Spring應用上下文,采用xml配置
//ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
//通過Spring上下文獲取Bean,在這裏Spring通過自動掃描發現了PersonHelloWorld的實現,並自動創建bean。
HelloWorldApi hwapi = ac.getBean(HelloWorldApi.class);
//通過sayHello()的輸入內容可以看到,hwapi為PersonHelloWorld的實例
hwapi.sayHello();
}
}
通過上的代碼,在控制臺會輸出下面的內容 “Hello World,This Is Person!”
Spring容器通過組件掃描發現了PersonHelloWorld類,並為它創建了對應的bean。到此為止,我們通過簡單的註解實現自動化裝配,在上面的案例中,HelloWorldConfig配置類@ComponentSan如果沒有其他配置,只會掃描HelloWorldConfig所在包或者它的子包,如果需要制定掃描的包,可以通過
@ComponentScan("com.seven.springTest")
或者
@ComponentScan(basePackages="com.seven.springTest")
basePackages允許設置多個包,,只需要把basePackages熟悉設置成一個數組即可
@ComponentScan(basePackages={"com.seven.springTest.service","com.seven.springTest.impl"})
除了通過java配置類來設置Spring啟用組件掃描,還可能通過xml類顯式配置,參考下面xml配置,並在獲取Spring應用上下文時通過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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 啟用Spring組件掃描-->
<context:component-scan base-package="com.seven.springTest"></context:component-scan>
</beans>
在上面的案例中,我們通過@Component和@ComponentScan來隱式的配置完成了Bean的裝配工作,接下來我們深入的探討下@Component和@ComponentScan
Spring容器在管理Bean的時候,會給每一個Bean有一個ID標識,上面的例子,如果HelloWorldApi的實現類有多個,那麽Spring容器該怎麽分配Bean呢,如果我們在使用@Component的時候,沒有明確的給PersonHelloWorld設置一個ID,Spring容器會默認給bean給定一個ID,一般為類名(第一個字母會變為小寫,例如跑personHelloWorld),所以下面的代碼也是成立的
//通過bean的ID來獲取實例
HelloWorldApi hwapi = (HelloWorldApi) ac.getBean("personHelloWorld");
hwapi.sayHello();
同時我們也可以為bean設置ID,如下:
@Component("person") //為bean設置ID為“person”
public class PersonHelloWorld implements HelloWorldApi {
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("Hello World,This Is Person!");
}
}
這樣我們在獲取bean的時候就可通過ID來獲取,如下:
// 根據設置的bean ID來獲取bean
HelloWorldApi hwapi = (HelloWorldApi) ac.getBean("person");
在以上的案例中我們使用了@Component和@ComponentScan實現了組件掃描,目前為止我們都是對單一的對象進行操作,如果程序復雜點,對象之間存在依賴,該如何處理呢?下面我們就來研究下如何為bean添加註解實現自動裝配
@AutoWired
在上面的案例中Person對整個世界說了一句Hello,可說話只有旁邊的人知道,我們需要讓更多的聽到我們的“hello world”,我們就需要一些工具,我們使用電視來廣播就能讓更多的人聽到了,首先我們定義一個傳播工具接口
package com.seven.springTest.service;
public interface TransmittingTool {
void work(String message);
}
接下來我們來創建我們的TV
package com.seven.springTest.service.impl;
import org.springframework.stereotype.Component;
import com.seven.springTest.service.TransmittingTool;
@Component //設置為需要被掃描到的組件
public class TVTool implements TransmittingTool {
@Override
public void work(String message) {
//傳播工具工作,把我們的消息傳播出去
System.out.println(message);
}
}
接下來我們需要對我們之前的PersonHelloWorld的sayHello()方法進行一些修改,讓它可以通過傳播工具來對全世界說Hello
package com.seven.springTest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.seven.springTest.service.HelloWorldApi;
import com.seven.springTest.service.TransmittingTool;
@Component
public class PersonHelloWorld implements HelloWorldApi {
//定義傳播工具
@Autowired //1.直接變量添加註解
private TransmittingTool transmittingTool;
// @Autowired //2. 通過構造函數註入依賴
// public PersonHelloWorld(TransmittingTool transmittingTool) {
// this.transmittingTool = transmittingTool;
// }
// @Autowired //3. 通過屬性的Setter方法註入依賴
// public void setTransmittingTool(TransmittingTool transmittingTool) {
// this.transmittingTool = transmittingTool;
// }
// @Autowired //4. 通過其他函數註入依賴
// public void inserttool(TransmittingTool transmittingTool){
// this.transmittingTool=transmittingTool;
// }
@Override
public void sayHello() {
// 通過傳播工具來sayHello
transmittingTool.work("Hello World,This Is Person!--form TV");
}
}
首先我們定義了一個傳播工具,這個工具的具體實現我們不清楚,需要Spring容器去給我註入依賴。
@Autowired直接可以使用在類變量、構造函數、Setter和其他任何方法上,參考代碼中1-4的實現
- 直接在變量上添加註解
- 在構造函數上添加註解,在spring容器通過構造器實例化bean的時候,會傳入一個提供給transmittingTool的實例,註入依賴;
- 通過Setter方法或者其他函數,Spring在初始化bean以後,會盡量的去滿足bean的所有依賴,如果使用第4個種註入,我們在HelloWorldTest中重來沒有調用過inserttool()方法,可是sayHello()還是能正常執行,Spring會去根據@Autowired來盡量嘗試去註入PersonHelloWorld的依賴。
如果能夠配置到1個滿足要求的依賴,那麽這個被依賴的bean就會被裝配進來,如果沒有匹配的依賴bean,那麽應用上下文創建的時候,Spring會拋出一個異常,為了避免異常,我們可以把@Autowired的required設置為false;
@Autowired(required=false) //2. 通過構造函數註入依賴
public PersonHelloWorld(TransmittingTool transmittingTool) {
this.transmittingTool = transmittingTool;
}
@Autowired的required設置給false後,Spring為嘗試給bean自動裝配,註入依賴,如果沒有匹配的bean的話,Spring將會讓這個bean處於未裝配的狀態,當時把required設置為false的時需要註意,因為這個依賴bean處於未裝配狀態,在調用依賴的時候,如果你的代碼做null的檢查,這個處於未裝配狀態的屬性有可能會發生異常。
如果有多個bean能滿足依賴關系的話,Spring也會拋出異常,表明沒有明確指出選擇哪個bean進行自動裝配。這個在後面我會單獨開一篇講解Spring的高級裝配,到時候在詳細說明,大家可以關註後續的文章。
自動化裝配Bean