Spring bean注冊(cè)到容器的總結(jié)
本文總結(jié)的是如何使用注解方式把對(duì)象加入ioc容器管理(永無(wú)止境,一直會(huì)更新).
來(lái)自作者的吐槽:好煩,他媽的提供這么多用法,然后那些 SpringBoot starter 框架里都是想用什么就用什么,導(dǎo)致看源碼理解度很痛苦,其實(shí)我感覺(jué)種類(lèi)方式多了,反而丟失了規(guī)范,增加理解成本,真的很煩?。。。。。。。?!
注意:所有的使用方式皆來(lái)自Spring framework, SpringBoot不在本文討論之內(nèi)。
@Component + @ComponentScan
首先上場(chǎng)的運(yùn)用最常用、最廣泛的方式。元注解延伸出去的@Controller、@Service、@Repository等都一樣。
容器bean名稱(chēng):默認(rèn)就是類(lèi)名首字母小寫(xiě)(app)
建議使用場(chǎng)景:自己項(xiàng)目中的類(lèi)需要交給Spring管理。
@Component public class App { }
@Configuration + @Bean
其實(shí)@Configuration也是@Component,所以你用@Component也可以,至于為什么要這樣設(shè)計(jì),應(yīng)該為了見(jiàn)名知意??梢酝ㄟ^(guò)@Bean的方式來(lái)自己構(gòu)建代碼的方式來(lái)構(gòu)建bean對(duì)象,然后塞入到Spring中,可以類(lèi)似Spring會(huì)回調(diào)你的@Bean上的方法,將你自己定義創(chuàng)建的對(duì)象注入到Spring,你可以自己定義構(gòu)造初始化等等。
容器bean名稱(chēng):默認(rèn)就是對(duì)應(yīng)方法名(a)
建議使用場(chǎng)景:比如在引入的jar包里的對(duì)象,你想加入到Spring中,一般會(huì)用這個(gè)。還有就是你想定義類(lèi)生成的具體過(guò)程,這個(gè)方式比較靈活。
@Configuration public class AppConfiguration { @Bean public A a() { return new A("junmo", 27); } }
@Import
說(shuō)起這個(gè)注解之前請(qǐng)你一定看看官方的說(shuō)明
/** * 用于導(dǎo)入一個(gè)或多個(gè)<em>組件類(lèi)</em>,通常是{@link Configuration @Configuration}類(lèi)。 * * <p>功能類(lèi)似于Spring XML中的{@code <import/>}元素。 * 允許導(dǎo)入{@code @Configuration}類(lèi)、{@link ImportSelector}和 * {@link ImportBeanDefinitionRegistrar}的實(shí)現(xiàn)類(lèi),以及普通的組件類(lèi)(從4.2開(kāi)始支持,類(lèi)似于 * {@link AnnotationConfigApplicationContext#register}方法的功能)。 * * <p>在導(dǎo)入的{@code @Configuration}類(lèi)中定義的{@code @Bean}可以通過(guò) * {@link org.springframework.beans.factory.annotation.Autowired @Autowired}注解注入。 * 開(kāi)發(fā)者可以選擇直接注入Bean,也可以注入聲明該Bean的配置類(lèi)的實(shí)例,后者便于在IDE中快速導(dǎo)航配置方法。 * * <p>該注解可以直接用在類(lèi)上,也可以作為元注解被其他注解使用。 * * <p>如果需要導(dǎo)入XML或其他非{@code @Configuration}的資源,應(yīng)使用 * {@link ImportResource @ImportResource}注解。 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { /** * 指定要導(dǎo)入的類(lèi),包括以下幾類(lèi): * 1. 標(biāo)注為{@link Configuration @Configuration}的類(lèi)。 * 2. 實(shí)現(xiàn)了{(lán)@link ImportSelector}接口的類(lèi)。 * 3. 實(shí)現(xiàn)了{(lán)@link ImportBeanDefinitionRegistrar}接口的類(lèi)。 * 4. 普通的組件類(lèi)。 */ Class<?>[] value(); }
1. @Import(簡(jiǎn)單)
@Import({A.class, B.class}) @Configuration public class App { }
從這里示例上能看出來(lái),用法比較簡(jiǎn)單,感覺(jué)跟@Component一樣無(wú)腦快速。而且它支持批量哦!
容器bean名稱(chēng):默認(rèn)就是全類(lèi)名(xxx.xxx.App)
建議使用場(chǎng)景: 這個(gè)注解就有說(shuō)明,指示要導(dǎo)入的一個(gè)或多個(gè)組件類(lèi),批量簡(jiǎn)單快速導(dǎo)入一堆對(duì)象,可以用這個(gè)。(前提是這個(gè)類(lèi)不是你項(xiàng)目中的類(lèi),是從外邊引入的類(lèi),而且需要加入到 ioc 中,不然@Component也可以做到)
缺點(diǎn):很明顯這個(gè)方式對(duì)于構(gòu)建復(fù)雜對(duì)象初始化不太適合,不如@Bean。
2. @Import+實(shí)現(xiàn)ImportSelector接口(這個(gè) SpringBoot 瘋狂用它)
很明顯這個(gè)可以寫(xiě)代碼在運(yùn)行時(shí)自己定義加入。這樣的好處是我可以選擇哪些對(duì)象加入到 ioc 中,畢竟只認(rèn)最后的返回 String[].
@Import(MyImportSelector.class) @Configuration public class App { } public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // importingClassMetadata:這個(gè)是目標(biāo)類(lèi)上的注解, 就是上面 App 類(lèi)上的所有注解(@Import, @Configuration)有什么用?能力有限, 暫時(shí)未知 haha // 這里可以擇別一些條件選擇性加載 if(xxxxxxxxx) { return new String[]{"com.dao.daocloud.A", "com.dao.daocloud.B"}; } else { return new String[]{"com.dao.daocloud.A", "com.dao.daocloud.C"}; } } } }
容器bean名稱(chēng):默認(rèn)就是全類(lèi)名(xxx.xxx.App)
建議使用場(chǎng)景: 也支持批量,同時(shí)你的項(xiàng)目中需要澤別條件,選擇性的加載 bean,可以用這個(gè)。
缺點(diǎn):很明顯這個(gè)方式對(duì)于構(gòu)建復(fù)雜對(duì)象初始化不太適合,不如@Bean,而且還要實(shí)現(xiàn)一個(gè)接口,比較繁瑣。
3. @Import+實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口
這個(gè)最大的好處是可以拿到 ioc bean注冊(cè)器(BeanDefinitionRegistry),它的作用很多,也就是你可以為所欲為在程序中.
@Import(MyImportBeanDefinitionRegistrar.class) @Configuration public class App { } public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { // 這個(gè) A 就是你的對(duì)象類(lèi) BeanDefinition aBeanDefinition = new RootBeanDefinition(A.class); registry.registerBeanDefinition("可以定義自己的bean名稱(chēng)", aBeanDefinition); } }
容器bean名稱(chēng):可以自己定義 bean 名稱(chēng)
建議使用場(chǎng)景: 對(duì)比上面兩種,這個(gè)可以拿到BeanDefinitionRegistry,可以自己定義 bean 名稱(chēng),還可以做一些別的事.
FactoryBean(非注解)
從第一眼看上去,翻譯下就是工廠 bean,看意思就是知道這個(gè)方式可以來(lái)生產(chǎn)出 bean 對(duì)象,它其實(shí)就是用了一個(gè)載體來(lái)生產(chǎn) bean,它本身也是一個(gè) bean,它的用法與上面幾種完全不一樣。形象舉個(gè)例子:這個(gè)就像是一個(gè)冰壺(FactoryBean)放了水(bean),冰壺可以倒出水。
@Component // 當(dāng)然這里你也可以用 @Bean 把它加載到 ioc 中 public class AFactoryBean implements FactoryBean<A> { @Override public A getObject() throws Exception { // 這里感覺(jué)就和@Bean一樣,可以自己構(gòu)建自己的對(duì)象并且初始化. return new A("junmo", 27); } @Override public Class<?> getObjectType() { // 這個(gè)我就不理解了,為什么要提供這個(gè)?不是在 getObject 對(duì)象都能拿到,Class 信息還拿不到嗎,還要開(kāi)發(fā)者必須重寫(xiě)實(shí)現(xiàn)這個(gè)方法,不理解,不知道什么樣的場(chǎng)景會(huì)用到這個(gè)方法。 return A.class; } @Override // 這個(gè)是設(shè)置單例還是多例的,不在本文討論范圍之內(nèi),但是你要知道它可以做到這個(gè)事情 public boolean isSingleton() { return FactoryBean.super.isSingleton(); } }
容器bean名稱(chēng):這個(gè)有點(diǎn)特殊。它的 bean 名稱(chēng)在 ioc 容器中會(huì)是AFactoryBean,然后你拿到的對(duì)象類(lèi)確會(huì)是 A.class。(很明顯它調(diào)用getObject方法給你生產(chǎn)對(duì)象了,也就是說(shuō)它為什么叫FactoryBean的含義)
建議使用場(chǎng)景: 動(dòng)態(tài)對(duì)象創(chuàng)建、根據(jù)條件生成不同 Bean、創(chuàng)建代理類(lèi)、生成多實(shí)例或生命周期管理需求。但是我覺(jué)得與@Bean也沒(méi)多大區(qū)別。但是外面很多框架都用了這個(gè)方式來(lái)定義 bean。還是有個(gè)區(qū)別,因?yàn)樗鼤?huì)調(diào)用 getObject方法來(lái)生產(chǎn)對(duì)象,這個(gè)可以在項(xiàng)目運(yùn)行后也可以生效,可以動(dòng)態(tài)改生成 bean 的方式。
另外說(shuō)一句:如果你要獲取AFactoryBean本身對(duì)象,可以用在前面加"&"來(lái)獲取該對(duì)象,算了,這個(gè)不重要,一般不太會(huì)用到(從下面源碼中很好理解).
public interface BeanFactory { /** * Used to dereference a {@link FactoryBean} instance and distinguish it from * beans <i>created</i> by the FactoryBean. For example, if the bean named * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject} * will return the factory, not the instance returned by the factory. */ String FACTORY_BEAN_PREFIX = "&"; }
到此這篇關(guān)于Spring bean注冊(cè)到容器的總結(jié)的文章就介紹到這了,更多相關(guān)Spring bean注冊(cè)到容器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java通過(guò)模擬post方式提交表單實(shí)現(xiàn)圖片上傳功能實(shí)例
這篇文章主要介紹了java通過(guò)模擬post方式提交表單實(shí)現(xiàn)圖片上傳功能實(shí)例,涉及Java針對(duì)表單的提交操作響應(yīng)及文件傳輸?shù)南嚓P(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11微信公眾平臺(tái)開(kāi)發(fā)實(shí)戰(zhàn)Java版之微信獲取用戶基本信息
這篇文章主要介紹了微信公眾平臺(tái)開(kāi)發(fā)實(shí)戰(zhàn)Java版之微信獲取用戶基本信息 的相關(guān)資料,需要的朋友可以參考下2015-12-12java中如何使用BufferedImage判斷圖像通道順序并轉(zhuǎn)RGB/BGR
這篇文章主要介紹了java中如何BufferedImage判斷圖像通道順序并轉(zhuǎn)RGB/BGR的相關(guān)資料,需要的朋友可以參考下2017-03-03IDEA新建JAVA項(xiàng)目簡(jiǎn)單圖文教程
這篇文章主要給大家介紹了關(guān)于IDEA新建JAVA項(xiàng)目的相關(guān)資料,IDEA是現(xiàn)在java中最為常用的編譯器,所以如何使用IDEA來(lái)創(chuàng)建java項(xiàng)目呢,這里給大家總結(jié)下,需要的朋友可以參考下2023-08-08