一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Spring多種加載Bean方式解析

Spring多種加載Bean方式解析

2020-09-17 15:41atheva Java教程

本篇文章主要介紹了Spring多種加載Bean方式解析,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

1 定義bean的方式

常見的定義Bean的方式有:

通過xml的方式,例如:

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

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

?
1
2
3
4
@Component
public class xxxServicer{
 ....
}

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

?
1
2
3
4
5
6
7
@Configuration
public class xxxConfiguration{
 @Bean
 public myBean myBean(){
   return new myBean();
 }
}

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

Spring多種加載Bean方式解析

2 BeanDefinition

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

Spring多種加載Bean方式解析

下面簡(jiǎn)單說一下各個(gè)子類:

  1. RootBeanDefinition和ChildBeanDefinition: 這2個(gè)BeanDefinition是相對(duì)的關(guān)系,自Spring 2.5 出來以后,已經(jīng)被GenericBeanDefinition代替。因?yàn)檫@樣強(qiáng)迫我們?cè)诰帉懘a的時(shí)候就必須知道他們之間的關(guān)系。
  2. GenericBeanDefinition: 相比于RootBeanDefinition和ChildBeanDefinition在定義的時(shí)候就必須硬編碼,GenericBeanDefinition的優(yōu)點(diǎn)可以動(dòng)態(tài)的為GenericBeanDefinition設(shè)置parent。
  3. AnnotatedBeanDefinition:看名字就是知道是用來讀取通過注解定義Bean。

3 通過xml文件定義Bean

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

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

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

4.1 <context:component-scan/>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public 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)簽就是注冊(cè)到Spring中
  Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
  registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
  return null;
}

4.2 @ComponentScan

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

其實(shí)簡(jiǎn)單來說,在處理@Configuration的時(shí)候發(fā)現(xiàn)有@ComponentScan注解,就會(huì)生成ComponentScanAnnotationParser去掃描@Component注解

4.3 ClassPathBeanDefinitionScanner

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

5 通過@Bean方式

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
    TrackedConditionEvaluator trackedConditionEvaluator) {
 
    //如果自己是通過@Import注解定義的,那么需要把自己注冊(cè)到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實(shí)例化

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@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最后最后實(shí)例的代碼,在AbstractAutowireCapableBeanFactory中

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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;
}

從上面初始化可以看出,InitializeBean和BeanPostProcessors的調(diào)用順序

7 總結(jié)

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

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://www.cnblogs.com/lizo/p/6759080.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 网友自拍偷拍 | 欧美一级片免费在线观看 | 日本人护士免费xxxx视频 | 国产91素人搭讪系列天堂 | 大陆国产vs国产对白 | 高中生喷水喷浆 | 好男人免费高清在线观看2019 | 好大好硬好紧太深了受不了 | 纲手被强喷水羞羞漫画 | 60岁了天天要小伙子 | 黑人好大 | 无码专区aaaaaa免费视频 | 日本搜子同屋的日子2国语 日本爽p大片免费观看 | 草逼视频免费看 | 特黄一级大片 | 国产精品美女久久久久 | 国产精品玖玖玖影院 | 欧美久在线观看在线观看 | 91po国产在线高清福利 | 性欧美xxxxx高清 | 情侣奴伺候女王第2部分小说 | 性春院| 色综合天天网 | 99re5精品视频在线观看 | 美女被躁了在线观看视频 | 成人亚洲欧美日韩中文字幕 | 日本不卡高清免费v日本 | 恩不要好大好硬好爽3p | 四虎在线永久免费视频网站 | 无罩看奶禁18 | 国产全部视频 | 亚洲国产精品嫩草影院永久 | 欧美破苞合集 magnet | 久久人妻熟女中文字幕AV蜜芽 | 国产乱子伦真实china | 日本96在线精品视频免费观看 | 第一次破苞h| 国产精品九九久久一区hh | 国产精品久久久久久影视 | 亚洲国产成人在线 | 亚洲成在人网站天堂一区二区 |