亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring多種加載Bean方式解析

 更新時間:2017年04月25日 08:24:47   作者:atheva  
本篇文章主要介紹了Spring多種加載Bean方式解析,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

1 定義bean的方式

常見的定義Bean的方式有:

通過xml的方式,例如:

<bean id="dictionaryRelMap" class="java.util.HashMap"/>

通過注解的方式,在Class上使用@Component等注解,例如

@Component
public class xxxServicer{
 ....
}

通過在@Configuration類下的@Bean的方式,例如

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

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

2 BeanDefinition

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

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

  1. RootBeanDefinition和ChildBeanDefinition: 這2個BeanDefinition是相對的關系,自Spring 2.5 出來以后,已經被GenericBeanDefinition代替。因為這樣強迫我們在編寫代碼的時候就必須知道他們之間的關系。
  2. GenericBeanDefinition: 相比于RootBeanDefinition和ChildBeanDefinition在定義的時候就必須硬編碼,GenericBeanDefinition的優(yōu)點可以動態(tài)的為GenericBeanDefinition設置parent。
  3. AnnotatedBeanDefinition:看名字就是知道是用來讀取通過注解定義Bean。

3 通過xml文件定義Bean

通過xml定義Bean是最早的Spring定義Bean的方式。因此,怎么把xml標簽解析為BeanDefinition(), 入口是在org.springframework.beans.factory.xml.XmlBeanDefinitionReader這個類,但是實際干活的是在org.springframework.beans.factory.xml.BeanDefinitionParserDelegate。代碼很多,但實際邏輯很簡單,就是解析Spring定義的<bean> <property> 等標簽 。

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

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

4.1 <context:component-scan/>

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

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    //獲取base-package標簽
  String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
  basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
  String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
      ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

  // 實際處理類是ClassPathBeanDefinitionScanner 
  ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
  //掃描basePackage下所有的類,如果有@Component等標簽就是注冊到Spring中
  Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
  registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
  return null;
}

4.2 @ComponentScan

注解對應生成的類是org.springframework.context.annotation.ComponentScanAnnotationParser 其實最后實際干活的還是ClassPathBeanDefinitionScanner這個。ComponentScanAnnotationParser類的生成是伴隨著@Configuration這個注解處理過程中(意思說@ComponentScan必須和@Configuration一起使用)。而處理@Configuration其實是org.springframework.context.annotation.ConfigurationClassPostProcessor。是不是感覺有點繞。

其實簡單來說,在處理@Configuration的時候發(fā)現有@ComponentScan注解,就會生成ComponentScanAnnotationParser去掃描@Component注解

4.3 ClassPathBeanDefinitionScanner

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

5 通過@Bean方式

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

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());
}

6 把BeanDefinition實例化

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

 @Override
 public void preInstantiateSingletons() throws BeansException {
   for (String beanName : beanNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      if (isFactoryBean(beanName)) {
        final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
        boolean isEagerInit;
        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
          isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
            @Override
            public Boolean run() {
              return ((SmartFactoryBean<?>) factory).isEagerInit();
            }
          }, getAccessControlContext());
        }
        else {
          isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
        }
        if (isEagerInit) {
          getBean(beanName);
        }
      }
      else {
        getBean(beanName);
      }
    }
  }
}

通過getBean最后最后實例的代碼,在AbstractAutowireCapableBeanFactory中

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()) {
    // 調用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()) {
    // 調用BeanPostProcessors#postProcessAfterInitialization
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }
  return wrappedBean;
}

從上面初始化可以看出,InitializeBean和BeanPostProcessors的調用順序

7 總結

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • java 日期各種格式之間的相互轉換實例代碼

    java 日期各種格式之間的相互轉換實例代碼

    這篇文章主要介紹了java 日期各種格式之間的相互轉換實例代碼的相關資料,需要的朋友可以參考下
    2017-02-02
  • Java并發(fā)程序刺客之假共享的原理及復現

    Java并發(fā)程序刺客之假共享的原理及復現

    前段時間在各種社交平臺“雪糕刺客”這個詞比較火,而在并發(fā)程序中也有一個刺客,那就是假共享。本文將通過示例詳細講解假共享的原理及復現,需要的可以參考一下
    2022-08-08
  • Spring?MVC啟動之HandlerMapping作用及實現詳解

    Spring?MVC啟動之HandlerMapping作用及實現詳解

    這篇文章主要為大家介紹了Spring?MVC啟動之HandlerMapping作用及實現詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • Java利用MYSQL LOAD DATA LOCAL INFILE實現大批量導入數據到MySQL

    Java利用MYSQL LOAD DATA LOCAL INFILE實現大批量導入數據到MySQL

    Mysql load data的使用,MySQL的LOAD DATAINFILE語句用于高速地從一個文本文件中讀取行,并裝入一個表中
    2018-03-03
  • 10分鐘在服務器部署好Jenkins的詳細過程

    10分鐘在服務器部署好Jenkins的詳細過程

    這篇文章主要介紹了10分鐘在服務器部署好Jenkins,本文主要是?Jenkins?的安裝部署,那前提我們應該裝好?Git?Maven?JDK,準備工作本文不給大家詳細介紹了,對服務器部署Jenkins相關知識感興趣的朋友一起看看吧
    2022-08-08
  • java 文件的操作Path、Paths、Files詳解

    java 文件的操作Path、Paths、Files詳解

    Java NIO(New I/O)是Java 7中引入的一項重要特性,旨在提供一種更加靈活和高效的文件處理方式,NIO.2主要通過Path、Paths和Files三個核心組件來實現對文件和目錄的操作,本文給大家介紹java 文件的操作Path、Paths、Files的相關知識,感興趣的朋友一起看看吧
    2024-10-10
  • Java如何使用遞歸查詢多級樹形結構數據(多級菜單)

    Java如何使用遞歸查詢多級樹形結構數據(多級菜單)

    這篇文章主要介紹了Java如何使用遞歸查詢多級樹形結構數據(多級菜單),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 通過實例了解Java jdk和jre的區(qū)別

    通過實例了解Java jdk和jre的區(qū)別

    這篇文章主要介紹了通過實例了解Java jdk和jre的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • mybatis高級映射一對多查詢實現代碼

    mybatis高級映射一對多查詢實現代碼

    本篇文章主要介紹了mybatis高級映射一對多查詢實現代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • spring的13個經典面試題

    spring的13個經典面試題

    Spring框架是一個開放源代碼的J2EE應用程序框架,是針對bean的生命周期進行管理的輕量級容Spring解決了開發(fā)者在J2EE開發(fā)中遇到的許多常見的問題,我們這篇文章就來了解一下spring的面試題
    2021-06-06

最新評論