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