Spring學習系列(二) 自動化裝配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的實現

  1. 直接在變量上添加注解
  2. 在構造函數上添加注解,在spring容器通過構造器實例化bean的時候,會傳入一個提供給transmittingTool的實例,注入依賴;
  3. 通過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的高級裝配,到時候在詳細說明,大家可以關注后續的文章。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM