中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

Spring多種加載Bean方式簡析-創(chuàng)新互聯(lián)

1 定義bean的方式

常見的定義Bean的方式有:

創(chuàng)新互聯(lián)主要從事成都網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)臨沭,十載網(wǎng)站建設(shè)經(jīng)驗(yàn),價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
  • 通過xml的方式,例如:

    <bean id="dictionaryRelMap" class="java.util.HashMap"/>
  • 通過注解的方式,在Class上使用@Component等注解,例如

    @Componentpublic class xxxServicer{
      ....
    }
  • 通過在@Configuration類下的@Bean的方式,例如

    Spring多種加載Bean方式簡析

    @Configurationpublic class xxxConfiguration{
      @Bean  public myBean myBean(){      return new myBean();
      }
    }

    Spring多種加載Bean方式簡析

雖然這三種定義Bean的方式不一樣,對應(yīng)的處理細(xì)節(jié)也不一樣,但是從大的邏輯上來看,都是一樣。主要的流程如下圖: 最關(guān)鍵的就是問題就是這么去找到定義Bean的方式,然后生成BeanDefinition后注冊到Spring上下文中,由Spring自動創(chuàng)建Bean的實(shí)例。

2 BeanDefinition

BeanDefinition是一個接口,用來描述一個Bean實(shí)例,例如是SINGLETON還是PROTOTYPE,屬性的值是什么,構(gòu)造函數(shù)的參數(shù)是什么等。簡單來說,通過一個BeanDefinition我們就可以完成一個Bean實(shí)例化。 BeanDefinition及其主要的子類:

下面簡單說一下各個子類:

  • RootBeanDefinition和ChildBeanDefinition: 這2個BeanDefinition是相對的關(guān)系,自Spring 2.5 出來以后,已經(jīng)被GenericBeanDefinition代替。因?yàn)檫@樣強(qiáng)迫我們在編寫代碼的時候就必須知道他們之間的關(guān)系。

  • GenericBeanDefinition: 相比于RootBeanDefinition和ChildBeanDefinition在定義的時候就必須硬編碼,GenericBeanDefinition的優(yōu)點(diǎn)可以動態(tài)的為GenericBeanDefinition設(shè)置parent。

  • AnnotatedBeanDefinition:看名字就是知道是用來讀取通過注解定義Bean。

3 通過xml文件定義Bean

通過xml定義Bean是最早的Spring定義Bean的方式。因此,怎么把xml標(biāo)簽解析為BeanDefinition(), 入口是在org.springframework.beans.factory.xml.XmlBeanDefinitionReader這個類,但是實(shí)際干活的是在org.springframework.beans.factory.xml.BeanDefinitionParserDelegate。代碼很多,但實(shí)際邏輯很簡單,就是解析Spring定義的<bean> <property> 等標(biāo)簽 。 之前寫過一篇文章介紹過如何自定義Spring標(biāo)簽 ,并解析后注冊到Spring中——傳送門

4 通過@Component等Spring支持的注解加載Bean

如果要使用@Component等注解定義Bean,一個前提條件是:有<context:component-scan/>或者@ComponentScan注解。但這2個方式還是有一點(diǎn)點(diǎn)區(qū)別:

4.1 <context:component-scan/>

由于<context:component-scan/>是一個xml標(biāo)簽,因此是在解析xml,生成的類org.springframework.context.annotation.ComponentScanBeanDefinitionParser,關(guān)鍵代碼:

Spring多種加載Bean方式簡析

@Overridepublic BeanDefinition parse(Element element, ParserContext parserContext) {        //獲取base-package標(biāo)簽
    String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
    basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
    String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);    // 實(shí)際處理類是ClassPathBeanDefinitionScanner 
    ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);    //掃描basePackage下所有的類,如果有@Component等標(biāo)簽就是注冊到Spring中
    Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
    registerComponents(parserContext.getReaderContext(), beanDefinitions, element);    return null;
}

Spring多種加載Bean方式簡析

4.2 @ComponentScan

注解對應(yīng)生成的類是org.springframework.context.annotation.ComponentScanAnnotationParser 其實(shí)最后實(shí)際干活的還是ClassPathBeanDefinitionScanner這個。ComponentScanAnnotationParser類的生成是伴隨著@Configuration這個注解處理過程中(意思說@ComponentScan必須和@Configuration一起使用)。而處理@Configuration其實(shí)是org.springframework.context.annotation.ConfigurationClassPostProcessor。是不是感覺有點(diǎn)繞。
其實(shí)簡單來說,在處理@Configuration的時候發(fā)現(xiàn)有@ComponentScan注解,就會生成ComponentScanAnnotationParser去掃描@Component注解

4.3 ClassPathBeanDefinitionScanner

上面說到了,無論注解還是標(biāo)簽的方式,最后都會交給ClassPathBeanDefinitionScanner這個類來處理,這個類做的就是1.掃描basePackage下所有class,如果有@Component等注解,讀取@Component相關(guān)屬性,生成ScannedGenericBeanDefinition,注冊到Spring中。

5 通過@Bean方式

前面說了@ComponentScan是在@Configuration處理過程中的一環(huán),既然@Bean注解也是必須和@Configuration一起使用,那么說明@Bean的處理也是在@Configuration中,其實(shí)最后是交給ConfigurationClassBeanDefinitionReader這個類來處理的,關(guān)鍵代碼:

Spring多種加載Bean方式簡析

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
        TrackedConditionEvaluator trackedConditionEvaluator) {       //如果自己是通過@Import注解定義的,那么需要把自己注冊到Spring中
    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }    //這里就是處理方法上的@Bean
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }    //處理@ImportResource,里面解析xml就是上面說到的解析xml的XmlBeanDefinitionReader    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

Spring多種加載Bean方式簡析

6 把BeanDefinition實(shí)例化

前面分別說了怎么把不同定義Bean的方式轉(zhuǎn)換為BeanDefinition加入到Spring中去(確切來說是保持在BeanFactory的BeanDefinitionMap中),實(shí)例化這些BeanDefinition是在ApplicationContext最后階段,關(guān)鍵代碼在DefaultListableBeanFactory中

Spring多種加載Bean方式簡析

  preInstantiateSingletons() = (!bd.isAbstract() && bd.isSingleton() && ! FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + (System.getSecurityManager() !=  && factory = AccessController.doPrivileged( PrivilegedAction<Boolean> ((SmartFactoryBean<?>= (factory  SmartFactoryBean &&<?>

Spring多種加載Bean方式簡析

通過getBean實(shí)例化BeanFactory,代碼是在AbstractAutowireCapableBeanFactory中

Spring多種加載Bean方式簡析

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {    //處理xxAware接口
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override            public Object run() {
                invokeAwareMethods(beanName, bean);                return null;
            }
        }, getAccessControlContext());
    }    else {
        invokeAwareMethods(beanName, bean);
    }
    Object wrappedBean = bean;    if (mbd == null || !mbd.isSynthetic()) {        // 調(diào)用BeanPostProcessors#postProcessBeforeInitialization
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }    try {       //初始化,先判斷是否是InitializingBean,        invokeInitMethods(beanName, wrappedBean, mbd);
    }    catch (Throwable ex) {        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }    if (mbd == null || !mbd.isSynthetic()) {        // 調(diào)用BeanPostProcessors#postProcessAfterInitialization
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }    return wrappedBean;
}

Spring多種加載Bean方式簡析

從上面初始化和注釋內(nèi)容可以看出,InitializeBean接口的方法(以及Init-method)和BeanPostProcessors的調(diào)用順序

7 總結(jié)

綜上分析,Spring加載Bean其實(shí)大的思想都是一樣的,先讀取相關(guān)信息生成BeanDefinition,然后通過BeanDefinition初始化Bean。如果知道了上面了套路以后,就可以清楚怎么自定義Xml標(biāo)簽或者自定義注解向Spring中注入Bean。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

名稱欄目:Spring多種加載Bean方式簡析-創(chuàng)新互聯(lián)
地址分享:http://www.rwnh.cn/article34/pdose.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、做網(wǎng)站移動網(wǎng)站建設(shè)、品牌網(wǎng)站制作、品牌網(wǎng)站設(shè)計、標(biāo)簽優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司
青州市| 九寨沟县| 嵩明县| 金坛市| 疏勒县| 彭水| 乌兰县| 井冈山市| 永济市| 包头市| 永福县| 射阳县| 祁门县| 辰溪县| 阳春市| 张家川| 石门县| 六盘水市| 津南区| 安乡县| 定西市| 沂源县| 许昌县| 东阳市| 五峰| 湖北省| 建平县| 滕州市| 山阳县| 新宁县| 渝北区| 光山县| 禄丰县| 永安市| 武川县| 门头沟区| 宜君县| 福州市| 阜新市| 邢台市| 旺苍县|