@Bean注解和@Configuration、@Component注解組合使用的區(qū)別
一、@Bean的“full”模式和“l(fā)ite”模式
在一般常見(jiàn)情況下,@Bean注解在@Configuration類(lèi)中聲明,稱(chēng)之為“full”模式;當(dāng)@Bean注解和@Component注解組合使用時(shí),稱(chēng)之為“l(fā)ite”模式。
這兩種組合使用的情況,初次看文檔時(shí)沒(méi)看明白,多看了幾次又跑了測(cè)試代碼,才大致理解了區(qū)別。
二、兩種模式的差異
如果只是把@Bean注解用在方法上,并且各個(gè)@Bean注解的方法之間沒(méi)有調(diào)用,上述兩種模式達(dá)到的效果基本相同,都可以把@Bean注解方法返回的對(duì)象作為bean注冊(cè)到容器中。
如果各個(gè)@Bean注解的方法之間有相互調(diào)用,那么兩種模式就會(huì)有很大的區(qū)別-與full模式下的@Configuration不同,lite模式下 @Bean方法互相調(diào)用無(wú)法聲明Bean之間的依賴(lài)關(guān)系。
這點(diǎn)在@Bean注解源碼注釋上也有說(shuō)明。
1、“full”模式下@Bean方法互相調(diào)用
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Configuration public class Config { @Bean() public C c(){ return new C(); } @Bean public B b(){ return new B(c()); } }
類(lèi)B:
public class B { public C c; public B(C a){this.c=a;} public void shutdown(){ System.out.println("b close..."); } }
類(lèi)C:
public class C { private String name; @PostConstruct public void init(){ this.name = "I am a bean"; } @Override public String toString(){ return "c say:" + name; } }
如上述所示代碼,我們有兩個(gè)類(lèi)B和C,在@Configuration類(lèi)中,使用兩個(gè)@Bean方法分別定義bean b 和bean c,但是需要注意的是new B(c()) 所在的@Bean方法調(diào)用了另一個(gè)@Bean方法。
測(cè)試主程序類(lèi):
import com.dxc.opentalk.springtest.config.B; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; @EnableAspectJAutoProxy @ComponentScan("com.dxc.opentalk.springtest") public class BootStrap { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BootStrap.class); B b = (B)applicationContext.getBean("b"); System.out.println(b.c); System.out.println(applicationContext.getBean("c")); System.out.println(applicationContext.getBean("c").equals(b.c)); } }
程序輸出結(jié)果:
c say:I am a bean
c say:I am a bean
true
可以看出bean c 被注入到了bean b 中,bean b中的成員 c 確實(shí)是Spring容器中的bean。(其實(shí),debug程序跟蹤Spring中的單例池更清晰,這里采用輸出結(jié)果說(shuō)明)
2、“l(fā)ite”模式下@Bean方法互相調(diào)用
還是上面的代碼,我們只把Config類(lèi)上的注解更換成@Component,其余代碼保持不變:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Component public class Config { @Bean() public C c(){ return new C(); } @Bean public B b(){ return new B(c()); } }
再看一下測(cè)試主程序類(lèi)輸出結(jié)果:
c say:null
c say:I am a bean
false
可以看到bean b中的c只是一個(gè)普通的c對(duì)象,并不是Spring容器中的bean(b中的c沒(méi)有執(zhí)行bean的初始化回調(diào)方法也和單例池中的c bean不相等)。所以這種模式下,@Bean方法互相調(diào)用不能完成bean之間相互依賴(lài)關(guān)系的注入。
三、總結(jié)
綜上所述,在使用@Bean注解時(shí)需要注意兩種模式的區(qū)別,一般情況下@Bean都是和@Configuration注解搭配使用的。
但是@Configuration注解的類(lèi)會(huì)被Spring使用CGLIB子類(lèi)化,所以@Configuration注解的類(lèi)不能用 final 修飾,而@Component注解沒(méi)有此限制。
如果使用@Bean注解和@Component注解組合需要完成bean之間相互依賴(lài)注入的話(huà),官方推薦采用構(gòu)造方法或者方法級(jí)別的依賴(lài)注入,如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Component public final class Config { @Bean() public C c(){ return new C(); } @Bean public B b(C c){//構(gòu)造方法注入 return new B(c); } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
通過(guò)volatile驗(yàn)證線(xiàn)程之間的可見(jiàn)性
這篇文章主要介紹了通過(guò)volatile驗(yàn)證線(xiàn)程之間的可見(jiàn)性,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10springboot 如何設(shè)置端口號(hào)和添加項(xiàng)目名
這篇文章主要介紹了springboot設(shè)置端口號(hào)和添加項(xiàng)目名的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08淺談一下RabbitMQ、Kafka和RocketMQ消息中間件對(duì)比
這篇文章主要介紹了淺談一下RabbitMQ、Kafka和RocketMQ消息中間件對(duì)比,消息中間件屬于分布式系統(tǒng)中一個(gè)字系統(tǒng),關(guān)注于數(shù)據(jù)的發(fā)送和接收,利用高效可靠的異步信息傳遞機(jī)制對(duì)分布式系統(tǒng)中的其余各個(gè)子系統(tǒng)進(jìn)行集成,需要的朋友可以參考下2023-05-05Java項(xiàng)目如何防止SQL注入(多種方案匯總)
SQL注入即是指web應(yīng)用程序?qū)τ脩?hù)輸入數(shù)據(jù)的合法性沒(méi)有判斷或過(guò)濾不嚴(yán),攻擊者可以在web應(yīng)用程序中事先定義好的查詢(xún)語(yǔ)句的結(jié)尾上添加額外的SQL語(yǔ)句,這篇文章主要介紹了?Java項(xiàng)目防止SQL注入的四種方案,需要的朋友可以參考下2023-12-12org.slf4j.Logger中info()方法的使用詳解
這篇文章主要介紹了org.slf4j.Logger中info()方法的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java判斷數(shù)字位數(shù)的方法總結(jié)
本文給大家整理了Java判斷數(shù)字位數(shù)的兩種常用方法,對(duì)此有興趣的可以跟著小編一起學(xué)習(xí)下。2018-02-02使用Java生成JWT(JSON Web Token)的方法示例
在現(xiàn)代應(yīng)用程序中,身份驗(yàn)證和授權(quán)是至關(guān)重要的,JWT是一種簡(jiǎn)單而強(qiáng)大的身份驗(yàn)證和授權(quán)機(jī)制,可以在Web應(yīng)用程序中安全地傳輸用戶(hù)信息,本文主要介紹了使用Java生成JWT的方法示例,感興趣的可以了解一下2024-03-03Spring Cloud升級(jí)最新Finchley版本的所有坑
這篇文章主要介紹了Spring Cloud升級(jí)最新Finchley版本的所有坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08