上面一篇文章中,學習了"Spring - 01 - 通過XML裝配Bean",下面學習自動化裝配Bean
自動化裝配Bean
Spring從兩個角度來實現自動化裝配
組件掃描:Spring會自動發現應用上下文中所創建的bean
自動裝配:Spring自動滿足bean之間的依賴
一、創建可被發現的bean
直接上代碼
package com.test.spring.server.test4;
/**
* Created by CYX on 2018/4/17.
*/
public interface CompactDisc {
void play();
}
package com.test.spring.server.test4;
import org.springframework.stereotype.Component;
/**
* @author CYX
* @create 2018-04-17-20:47
*/
//該註解表明該類會作爲組件類,並告知Spring要爲這個類創建bean。
@Component
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
applicationContext.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="com.test.spring.server.test4"/>
</beans>
通過XML啓用組件掃描
測試主類
package com.test.spring.server.test4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 測試組件掃描
*
* @author CYX
* @create 2018-04-17-21:08
*/
public class Test4App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/spring/test4/applicationContext.xml");
SgtPeppers sgtPeppers = context.getBean("sgtPeppers",SgtPeppers.class);
sgtPeppers.play();
}
}
輸出結果:
和之前 在XML中顯示配置Bean(Spring - 01 - 通過XML裝配Bean) 對比一下,我們並沒有在applicationContext.xml配置文件中配置<bean>元素用來顯示的聲明bean。
只是在需要創建bean對象的類上增加了一個註解@Component。
@Component註解的作用是 把普通pojo對象 實例化到Spring容器中,相當於applicationContext.xml配置文件中的:
<bean id="sgtPeppers" class="com.test.spring.server.test4.SgtPeppers"></bean>
Spring Framework 5.0.5.RELEASE API 的解釋:Indicates that an annotated class is a "component".
Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning.
表示註釋類是“組件”。
當使用基於註釋的配置和類路徑掃描時,這些類被認爲是自動檢測的候選對象。
當我們的類不屬於各種歸類時,我們就可以使用@Component來標註這個類。被標註的類,可以認爲是"組件"
不過這裏要注意,僅僅使用@Component註解時,我們並沒有指定bean 的id,默認使用類名的首字母小寫。
<context:component-scan>配置的作用是 開啓組件自動掃描
<context:component-scan base-package="com.test.spring.server.test4"/>的含義是,掃描com.test.spring.server.test4包下的所有註解。
二、爲組件掃描的bean命名
Spring應用 上下文 中所有的bean都會給定一個id。
在前面的例子中,我們並沒有明確的爲 SgtPeppers 指定 bean-id;
但Spring會爲其指定一個id,具體的講,這個bean所給定的id,爲 sgtPeppers,也就是將類名的第一個字母變爲小寫。
如果要爲這個bean設置不同的bean-id,需要將 期望id 作爲值,傳遞給@Component註解。
例如:
@Component("sssgtPeppers")
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
修改下主方法的bean id,其他不用修改,看下運行結果:
還有一種爲bean命名的方式,這種方式不使用@Component註解,而是使用Java依賴注入規範所提供的的@Named註解來設置。
注意:使用@Named註解,需要添加依賴
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Named("test4-sgtPeppers")
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
修改下主方法代碼,看下運行結果:
Spring支持將@Named作爲@Component註解的替代方案。
不過還是推薦@Component註解
三、使用Java Config自動裝配Bean
在上面代碼的基礎上修改一下
package com.test.spring.server.test4;
/**
* Created by CYX on 2018/4/17.
*/
public interface CompactDisc {
void play();
}
package com.test.spring.server.test4;
import javax.inject.Named;
/**
* @author CYX
* @create 2018-04-17-20:47
*/
//該註解表明該類會作爲組件類,並告知Spring要爲這個類創建bean。
//@Component("sgtPeppers")
//@Component("sssgtPeppers")
@Named("test4-sgtPeppers")
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
package com.test.spring.server.test4;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 類CDPlayerConfig通過Java代碼定義了Spring的裝配規則。
* <p>
* 在後面我們再詳細介紹
* <p>
* 這裏,我們只需要觀察一下CDPlayerConfig類並沒有顯示的聲明任何bean。
* <p>
* 只不過它使用了@ComponentScan註解,這個註解能夠在Spring中啓用組件掃描。
* <p>
* 如果沒有其他配置的話,@ComponentScan默認會掃描與配置類相同的包。
* <p>
* Spring將會掃描這個包以及這個包下所有的子包,查找帶有@Component註解的類。
*
* 這種方式,我們暫時註釋掉,使用XML來開啓組件掃描。
*
* @author CYX
* @create 2018-04-17-20:57
*/
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test4")
public class CDPlayerConfig {
}
package com.test.spring.server.test4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 測試組件掃描
*
* @author CYX
* @create 2018-04-17-21:08
*/
public class Test4App {
public static void main(String[] args) {
// ApplicationContext context = new ClassPathXmlApplicationContext("/spring/test4/applicationContext.xml");
ApplicationContext context =new AnnotationConfigApplicationContext(CDPlayerConfig.class);
SgtPeppers sgtPeppers = context.getBean("test4-sgtPeppers",SgtPeppers.class);
sgtPeppers.play();
}
}
注意:這裏我並沒有使用applicationContext.xml,將之前XML配置文件中的
<context:component-scan base-package="com.test.spring.server.test4"/>註釋掉,所以並沒有貼出來。
輸出結果:
創建Java Config類的關鍵在於爲其添加@Configuration註解。
@Configuration註解表明這個類是一個配置類,該類應該包含在Spring應用上下文中如何創建bean的細節。
@ComponentScan註解默認會掃描與配置類相同的包,以及這個包下面所有的子包。
然後查找帶有@Component註解,找到的話,就會爲他們創建bean實例。
四、通過爲bean添加註解實現自動裝配
自動裝配就是讓Spring自動滿足bean依賴的一種方法;
在滿足依賴的過程中,會在Spring應用上下文中尋找某個bean需求的其他bean。
爲了聲明要進行自動裝配,可以藉助Spring 的@Autowired註解
代碼優先
package com.test.spring.server.test05;
/**
* Created by CYX on 2018/4/17.
*/
public interface CompactDisc {
void play();
}
package com.test.spring.server.test05;
import org.springframework.stereotype.Component;
/**
* @author CYX
* @create 2018-04-30-17:09
*/
@Component
public class SayHello {
public SayHello() {
System.out.println("SayHello 默認構造器");
}
public void sayHelloWithName() {
System.out.println("SayHello :hello cyx");
}
public void sayHelloWithAddress() {
System.out.println("SayHello :hello 南京");
}
}
package com.test.spring.server.test05;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author CYX
* @create 2018-04-17-20:47
*/
@Component("sssgtPeppers")
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
// @Autowired
private SayHello sayHello;
/*@Autowired
public void setSayHello(SayHello sayHello) {
this.sayHello = sayHello;
}*/
@Autowired
public SgtPeppers(SayHello sayHello) {
this.sayHello = sayHello;
}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
sayHello.sayHelloWithAddress();
sayHello.sayHelloWithName();
}
}
applicationContext.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="com.test.spring.server.test05"/>
</beans>
主方法
package com.test.spring.server.test05;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 測試組件掃描
*
* @author CYX
* @create 2018-04-17-21:08
*/
public class Test5App {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/spring/test05/applicationContext05.xml");
SgtPeppers sgtPeppers = context.getBean("sssgtPeppers", SgtPeppers.class);
sgtPeppers.play();
}
}
運行結果:
@Autowired 註解不僅可以放在成員變量、setter方法上,還可以放在構造器上。
五、通過Java代碼裝配Bean
在上面,我們已經初步使用過通過Java Config來裝配Bean,下面詳細的瞭解一下。
代碼優先:
package com.test.spring.server.test06;
/**
* Created by CYX on 2018/4/17.
*/
public interface CompactDisc {
void play();
}
package com.test.spring.server.test06;
/**
* @author CYX
* @create 2018-04-17-20:47
*/
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
public SgtPeppers() {
}
public SgtPeppers(String title, String artist) {
this.title = title;
this.artist = artist;
}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
}
package com.test.spring.server.test06;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author CYX
* @create 2018-04-17-20:57
*/
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test06")
public class CDPlayerConfig {
@Bean(name = "sssgtPeppers")
public SgtPeppers initializationSgtPeppers() {
return new SgtPeppers("888888","99999");
}
}
主方法
package com.test.spring.server.test06;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 測試組件掃描
*
* @author CYX
* @create 2018-04-17-21:08
*/
public class Test6App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
SgtPeppers sgtPeppers = context.getBean("sssgtPeppers", SgtPeppers.class);
sgtPeppers.play();
}
}
主方法
注意:
SgtPeppers類中已經沒有 @Component 註解了。
SgtPeppers類 的實例化,在 CDPlayerConfig類中實現。
@Bean註解 會告訴Spring這個方法將會返回一個對象,該對象要註冊爲Spring應用上下文中的bean。
@Bean(name = "sssgtPeppers") 同時,我們還爲bean 設置了id。
在默認情況下,bean 的id 與帶有@Bean註解的方法名是一樣的。
在CDPlayerConfig類中進行bean 實例化的時候,咱們還可以對它進行一些初始化的操作。
這些都是根據業務來看...我這裏模擬的話,只是,傳入兩個參數。
六、藉助Java Config實現注入
代碼優先
package com.test.spring.server.test06;
/**
* Created by CYX on 2018/4/17.
*/
public interface CompactDisc {
void play();
}
package com.test.spring.server.test06;
/**
* @author CYX
* @create 2018-04-30-17:09
*/
public class SayHello {
public SayHello() {
System.out.println("SayHello 默認構造器");
}
public void sayHelloWithName() {
System.out.println("SayHello :hello cyx");
}
public void sayHelloWithAddress() {
System.out.println("SayHello :hello 南京");
}
}
package com.test.spring.server.test06;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author CYX
* @create 2018-04-17-20:47
*/
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Autowired
private SayHello sayHello;
public SgtPeppers() {
}
public SgtPeppers(SayHello sayHello) {
this.sayHello = sayHello;
}
public SgtPeppers(String title, String artist) {
this.title = title;
this.artist = artist;
}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
sayHello.sayHelloWithAddress();
sayHello.sayHelloWithName();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
}
package com.test.spring.server.test06;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author CYX
* @create 2018-04-17-20:57
*/
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test06")
public class CDPlayerConfig {
@Bean(name = "sssgtPeppers")
public SgtPeppers initializationSgtPeppers() {
return new SgtPeppers("888888", "99999");
}
@Bean
public SgtPeppers initializationSgtPeppersWithHello() {
return new SgtPeppers(initializationSayHello());
}
@Bean
public SayHello initializationSayHello() {
return new SayHello();
}
}
package com.test.spring.server.test06;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 測試組件掃描
*
* @author CYX
* @create 2018-04-17-21:08
*/
public class Test6App {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
SgtPeppers sgtPeppers = context.getBean("sssgtPeppers", SgtPeppers.class);
sgtPeppers.play();
}
}
運行結果:在CDPlayerConfig類中我們增加了兩個bean,一個是用來注入的,另一個是被注入的。
在initializationSgtPeppersWithHello()方法中,並沒有像之前那樣子,傳入參數,而是傳入一個對象(方法)
看起來,SayHello對象,是通過調用initializationSayHello()方法得來的,但情況並非如此。
因爲 initializationSayHello()方法上添加了@Bean註解,Spring將會攔截所有對它的調用,並確保直接返回該方法所創建的bean,而不是每次都對其進行實際的調用。
Java Config類換一種寫法:
package com.test.spring.server.test06;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author CYX
* @create 2018-04-17-20:57
*/
@Configuration
@ComponentScan(basePackages = "com.test.spring.server.test06")
public class CDPlayerConfig {
@Bean(name = "sssgtPeppers")
public SgtPeppers initializationSgtPeppers() {
return new SgtPeppers("888888", "99999");
}
@Bean
public SgtPeppers initializationSgtPeppersWithHello(SayHello sayHello) {
return new SgtPeppers(sayHello);
}
@Bean
public SayHello initializationSayHello() {
return new SayHello();
}
}
在這裏,initializationSgtPeppersWithHello(SayHello sayHello) 方法直接將對象傳入,這樣子,好理解一點。
參考文章:
https://www.cnblogs.com/Ming8006/p/6323633.html
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html
《Spring 實戰》