springboot啟動(dòng)流程2--初始化上下文構(gòu)建類

  • 前言

    上文已經(jīng)介紹了配置資源和環(huán)境初始化的過程蠢正。本節(jié)只講解createApplicationContext上下文應(yīng)用創(chuàng)建铲咨。

    文章基于springboot2.3.x系列的源碼(大部分以jar包中的源碼為例講解)溜徙,github的源碼與實(shí)際發(fā)版的可能略微不同琅关,不過整體流程差別不大舅世。
    本人第一次寫文章凄硼,如有錯(cuò)誤或誤導(dǎo)歡迎留言指正。文章整體可能比較啰嗦匠楚,盡可能的將流程中的每一個(gè)重要的方法都講到巍膘。

  • createApplicationContext 創(chuàng)建上下文應(yīng)用

    源碼:

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }
    
        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
    

    webApplicationType默認(rèn)值為SERVLET,這里對(duì)應(yīng)會(huì)獲取AnnotationConfigServletWebServerApplicationContext的class對(duì)象油啤。通過BeanUtils.instantiateClass實(shí)例化對(duì)象典徘,其實(shí)直接通過new創(chuàng)建出來效果一樣蟀苛,并且在以后版本的源碼中是直接使用new創(chuàng)建的益咬。這個(gè)類的作用通過名稱也可以知道,是基于注解形式的web上下文應(yīng)用構(gòu)建帜平。與之相對(duì)應(yīng)的是xml方式XmlServletWebServerApplicationContext幽告。

    先看一下這個(gè)關(guān)鍵類的uml圖:

applicationContext類圖.png

這里圖片上的字比較小,如果看不清也可以通過自己的idea去查看裆甩。關(guān)系比較復(fù)雜冗锁,但是可以在圖上看到幾個(gè)常見的類。BeanFactory嗤栓、ResourceLoader冻河、lifecycle等≤运В可以看出頂層的都是接口叨叙,下面的實(shí)現(xiàn)類也相互交叉,其公共的父類之一是ApplicationContext接口堪澎。

  • AnnotationConfigServletWebServerApplicationContext 初始化

    這里開始我們需要去了解AnnotationConfigServletWebServerApplicationContext的自身和其父類擂错,因?yàn)榈竭@里開始,有很多初始化動(dòng)作已經(jīng)在構(gòu)造函數(shù)內(nèi)進(jìn)行了樱蛤。

    從自身開始:

    public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
        private final AnnotatedBeanDefinitionReader reader;
        private final ClassPathBeanDefinitionScanner scanner;
        private final Set<Class<?>> annotatedClasses;
        private String[] basePackages;
    
        public AnnotationConfigServletWebServerApplicationContext() {
            this.annotatedClasses = new LinkedHashSet();
            this.reader = new AnnotatedBeanDefinitionReader(this);
            this.scanner = new ClassPathBeanDefinitionScanner(this);
        }
        
        ......
    
        //還有其他的構(gòu)造函數(shù)钮呀,這里我們只選啟動(dòng)流程默認(rèn)的無參構(gòu)造函數(shù)
        
    }
    

    構(gòu)造函數(shù)內(nèi)初始化3個(gè)參數(shù)剑鞍,其中 AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner 是兩個(gè)非常關(guān)鍵的類。一個(gè)是基于注解的bean定義爽醋,一個(gè)是基于路徑的bean掃描蚁署。

    我們老樣子逐個(gè)進(jìn)行分析。從這里也開始了無限套娃模式子房。說實(shí)話spring系列的源碼寫的真的很好形用,但也真的很難讀懂。

    AnnotatedBeanDefinitionReader
    從構(gòu)造函數(shù)開始:

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this(registry, getOrCreateEnvironment(registry));
    }
    
    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        //基于產(chǎn)生bean的注解证杭,若沒有指定bean的名稱將會(huì)自動(dòng)生成一個(gè)首字母小寫的名稱作為bean的名稱
        this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
        //Scop的代理模式
        this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        //這里指的是當(dāng)前的環(huán)境變量
        this.registry = registry;
        //條件注入bean
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }
    
    private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        return (Environment)(registry instanceof EnvironmentCapable ? ((EnvironmentCapable)registry).getEnvironment() : new StandardEnvironment());
    }
    

    先看一下getOrCreateEnvironment方法:
    方法主要是判斷了一下當(dāng)前AnnotationConfigServletWebServerApplicationContext是否是EnvironmentCapable子類田度,若是則返回當(dāng)前環(huán)境對(duì)象,若不是則初始化一個(gè)StandardEnvironment解愤。

    EnvironmentCapable主要是判斷當(dāng)前上限文是否具有提供環(huán)境屬性的能力镇饺。內(nèi)部只有一個(gè)getEnvironment方法,原設(shè)計(jì)是獲取一個(gè)不可修改的環(huán)境對(duì)象送讲。但是在ConfigurableApplicationContext對(duì)其進(jìn)行了重寫奸笤,使獲取的對(duì)象具有可再次定制的能力。

    吐槽一下很有迷惑的入?yún)?strong>BeanDefinitionRegistry哼鬓,這個(gè)接口與EnvironmentCapable沒有任何的關(guān)系监右,BeanDefinitionRegistry相當(dāng)于我們?cè)趯懘a時(shí)用的Object接受參數(shù)一樣,是ApplicationContext的父類异希。但是方法內(nèi)直接進(jìn)行了類型強(qiáng)轉(zhuǎn)健盒,雖然也沒有錯(cuò)。

AnnotationBeanNameGenerator:
基于注解生成bean的名稱称簿。若注解指定了則使用注解內(nèi)的扣癣,否則默認(rèn)將類名的首字母變成小寫作為名稱。

AnnotationScopeMetadataResolver:
設(shè)置bean的代理模式憨降,即我們常用的@Scop注解的實(shí)現(xiàn)父虑。在其構(gòu)造函數(shù)內(nèi)默認(rèn)設(shè)置ScopedProxyMode.NO 不使用代理。也就是單例模式授药,即bean是全局唯一的這樣可以避免反復(fù)的創(chuàng)建bean士嚎,提升服務(wù)性能,但也存在線程安全問題悔叽,其實(shí)很好理解莱衩,單例的bean也意味著若存在全局變量,就不能隨意更改否則變更后會(huì)有影響骄蝇。

ScopedProxyMode共有四種類型:
DEFAULT:等同于NO膳殷,不使用代理的單例模式。
NO:單例模式
INTERFACES:jdk動(dòng)態(tài)代理
TARGET_CLASS:CGLAB動(dòng)態(tài)代理

ConditionEvaluator:
自定義創(chuàng)建bean條件,注解@Condition的處理類赚窃〔嵴校可以按照條件進(jìn)行類加載,條件需要單獨(dú)定義勒极,并實(shí)現(xiàn)
Condition接口是掰。
例如:


public class MyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        ....
        return true;
    }
}

@Conditional({ MyCondition.class })
@Configuration
public class MyConfig {
 
    @Bean
    @Conditional({ MyCondition.class })
    public Date date() {
        return new Date();
    }

}

在springboot項(xiàng)目中很少使用了,springboot提供了更多的@Condition的擴(kuò)展注解辱匿,例如:@ConditionalOnMissingBean键痛,@ConditionalOnProperty,@ConditionalOnBean等匾七。

AnnotationConfigUtils.registerAnnotationConfigProcessors:
在給定的注冊(cè)表中注冊(cè)所有相關(guān)的注解后處理器絮短。比如提供@Autowired,@Value,@Order等注解的支持。所謂的后處理器昨忆,其實(shí)就是相關(guān)注解的支持類丁频。

源碼:

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        //獲取bean工廠 若是springboot我們這里已經(jīng)知道其為 DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            //加載順序機(jī)制
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            //決定一個(gè)bean定義是否應(yīng)該被視為自動(dòng)裝配的候選時(shí),為這個(gè)BeanFactory設(shè)置一個(gè)自定義的自動(dòng)裝配候選解析器
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
        //驗(yàn)證是否包含名稱org.springframework.context.annotation.internalConfigurationAnnotationProcessor的bean
        //若沒有則通過registerPostProcessor方法添加到registry中
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //將需要注冊(cè)的bean手動(dòng)封裝成RootBeanDefinition里面邑贴,用于描述bean的屬性和對(duì)bean進(jìn)行操作
            //@configuration支持
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //@Autowired席里、Value注解支持
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        //JSR-250是一個(gè)標(biāo)準(zhǔn),可以理解為java的約定或者說預(yù)留的注解拢驾,網(wǎng)上的定義為資源相關(guān)的處理
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
        // JPA約定
        if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition();
            try {
                def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                        AnnotationConfigUtils.class.getClassLoader()));
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        //異步監(jiān)聽器
        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
        }
        //監(jiān)聽器工廠
        if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
        }

        return beanDefs;
    }
    

源碼看起來比較多 但實(shí)際上邏輯很簡單奖磁,為了初始化一些spring自身資源類注解的支持,并注入成bean繁疤。類似于@Resource咖为,@Value等,bean內(nèi)屬性的注入嵌洼,并非@Service的類級(jí)注解案疲。

格外提一點(diǎn)擴(kuò)展知識(shí),上面的源碼中能看到一個(gè)jsr250Present 和 jpaPresent 著其實(shí)是java的兩個(gè)約定封恰。感興趣的可以去了解一下麻养,我只說一點(diǎn),比如:比如我們知道@Resource和@Autowired在很多情況下是可以互換的诺舔。

但是@Resource并非spring的注解鳖昌,而是java自帶的。很早以前就很困惑低飒,為何spring要提供一個(gè)java自身注解的支持许昨,難道不會(huì)和其他的框架或者jar沖突嗎?然而事實(shí)上的確會(huì)沖突褥赊,但這個(gè)@Resource是java制定的資源加載約定注解糕档,相當(dāng)于我提供了一個(gè)接口在這,并且我建議你們遵循這個(gè)約定去實(shí)現(xiàn)它拌喉。
這樣的注解不止@Resource一個(gè)速那,感興趣的可以去了解一下俐银。同理JPA也類似。

單看方法的話會(huì)有點(diǎn)奇怪端仰,這里的返回值不重要捶惜,關(guān)鍵是registerPostProcessor方法。

源碼:

    private static BeanDefinitionHolder registerPostProcessor(
            BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

        definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        //注入bean
        registry.registerBeanDefinition(beanName, definition);
        return new BeanDefinitionHolder(definition, beanName);
    }

方法內(nèi)registry.registerBeanDefinition注冊(cè)了spring的內(nèi)部bean荔烧。

這里講解的順序有問題吱七,下一篇我們將從頂層往下看,這篇是從底層往上看因此鹤竭,會(huì)有點(diǎn)莫名其妙踊餐。若看過源碼或調(diào)試過的小伙伴應(yīng)該知道到這里的時(shí)候其實(shí)已經(jīng)知道了,當(dāng)前上下文中使用的beanFactory是DefaultListableBeanFactory 這是一個(gè)非常關(guān)鍵的類臀稚,bean的整個(gè)加載流程都在內(nèi)部市袖,包括所謂的IOC容器,其實(shí)就是一個(gè)Map烁涌,這些都是后話了苍碟。

AnnotatedBeanDefinitionReader類的解析告一段落。

ClassPathBeanDefinitionScanner:
AnnotatedBeanDefinitionReader實(shí)現(xiàn)了bean內(nèi)屬性的組裝撮执。ClassPathBeanDefinitionScanner實(shí)現(xiàn)的是bean的掃描和加載微峰。

構(gòu)造函數(shù)源碼:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
        .... 與AnnotatedBeanDefinitionReader相同
        this.registry = registry;
        if (useDefaultFilters) {
            this.registerDefaultFilters();
        }
    }

protected void registerDefaultFilters() {
        //設(shè)置Component注解過濾器
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));
            this.logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        } catch (ClassNotFoundException var4) {
        }

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));
            this.logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        } catch (ClassNotFoundException var3) {
        }

    }

提供:Component、Repository抒钱、Service蜓肆、Controller注解的支持,源碼中只看到了配置Component,因?yàn)槠渌麕讉€(gè)注解都基于Component擴(kuò)展的,另外提供了javaEE 6的ManagedBean注解和JSR-330的Named注解支持谋币。
感興趣的可以去了解一下 JSR和JPA協(xié)議仗扬。

AnnotationConfigServletWebServerApplicationContext 類講解到此結(jié)束。

回到上面UMl圖蕾额,可以看到其擁有一個(gè)復(fù)雜的繼承關(guān)系早芭,并且上面也留了一個(gè)疑問,加載過程中的beanFactory是在什么地方初始化的诅蝶?

下面將依次看一下其父類的無參構(gòu)造函數(shù)都做了啥(接口除外)退个,大部分接口內(nèi)部沒有邏輯代碼。

按從下往上的方式去看:

ServletWebServerApplicationContext 無操作调炬。

GenericWebApplicationContext 無操作

GenericApplicationContext
源碼:

    public GenericApplicationContext() {
        this.customClassLoader = false;
        this.refreshed = new AtomicBoolean();
        // 初始化bean工廠
        this.beanFactory = new DefaultListableBeanFactory();
    }

這里已經(jīng)知道上下文中使用的beanFactory是DefaultListableBeanFactory類

AbstractApplicationContext
源碼:

 public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());
        this.id = ObjectUtils.identityToString(this);
        this.displayName = ObjectUtils.identityToString(this);
        this.beanFactoryPostProcessors = new ArrayList();
        this.active = new AtomicBoolean();
        this.closed = new AtomicBoolean();
        this.startupShutdownMonitor = new Object();
        this.applicationListeners = new LinkedHashSet();
        //特殊資源路徑的加載處理语盈,非classpath*:下的資源,如:file:C:/context.xml
        this.resourcePatternResolver = this.getResourcePatternResolver();
    }

DefaultResourceLoader
源碼:

    public DefaultResourceLoader() {
        this.classLoader = ClassUtils.getDefaultClassLoader();
    }
  • DefaultListableBeanFactory解析

構(gòu)造函數(shù)源碼:

注釋理解來自于源碼:

    public DefaultListableBeanFactory() {
        // 用于檢查bean定義是否為自動(dòng)裝配候選的解析程序
        this.autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;
        //從依賴項(xiàng)類型映射到相應(yīng)的自動(dòng)裝配值
        this.resolvableDependencies = new ConcurrentHashMap(16);
        //Bean定義對(duì)象的映射缰泡,以Bean名稱為鍵刀荒。
        this.beanDefinitionMap = new ConcurrentHashMap(256);
        //根據(jù)名稱合并 BeanDefinitionHolder持有的bean
        this.mergedBeanDefinitionHolders = new ConcurrentHashMap(256);
        //單例和非單例Bean名稱的映射,按依賴項(xiàng)類型進(jìn)行鍵控
        this.allBeanNamesByType = new ConcurrentHashMap(64);
        //僅依賴單例的bean名稱的映射,按依賴項(xiàng)類型進(jìn)行鍵控
        this.singletonBeanNamesByType = new ConcurrentHashMap(64);
        //Bean定義名稱列表缠借,按注冊(cè)順序
        this.beanDefinitionNames = new ArrayList(256);
        //手動(dòng)注冊(cè)的單例的名稱列表资溃,按注冊(cè)順序。
        this.manualSingletonNames = new LinkedHashSet(16);
    }

這個(gè)是jar包中的源碼烈炭,若從github獲取的源碼構(gòu)造函數(shù)內(nèi)可能并沒有溶锭,而是通過餓漢式的模式直接在定義屬性的時(shí)候就初始化了,這樣雖然寫著方便符隙,但看著并不直觀趴捅。

構(gòu)造函數(shù)內(nèi)初始化的Map們就是口中常說的IOC容器

那么bean的循環(huán)依賴時(shí)如何被解決的呢?先留一個(gè)疑問霹疫,在將bean加載的流程時(shí)候再說拱绑。

DefaultListableBeanFactory也有著很復(fù)雜的繼承關(guān)系,下面將結(jié)合UML圖進(jìn)行講解。

beanFactory UMl類圖.png

只看圖中藍(lán)色的實(shí)體類繼承關(guān)系。逐個(gè)類的構(gòu)造函數(shù)查看颈畸。構(gòu)造函數(shù)未必都是無參的采桃,具體執(zhí)行的哪一個(gè)要看子類是否有傳入特定參數(shù)般渡。

一般情況下,在非工具的實(shí)體類中很少有 static 的靜態(tài)代碼塊,因此不需要刻意去尋找。一般都是通過構(gòu)造函數(shù)完成初始化吧恃。

AbstractAutowireCapableBeanFactory

源碼:

    public AbstractAutowireCapableBeanFactory() {
        //基于CGLB的bean動(dòng)態(tài)代理創(chuàng)建(策略模式)
        this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
        //獲取方法或構(gòu)造函數(shù)的參數(shù)名稱,這里默認(rèn)通過java反射機(jī)制
        this.parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        //是否自動(dòng)嘗試解析bean之間的循環(huán)依賴
        this.allowCircularReferences = true;
        //在循環(huán)依賴的時(shí)候麻诀,是否可以注入原始的bean痕寓,應(yīng)該是為進(jìn)行屬性賦值的原始bean
        this.allowRawInjectionDespiteWrapping = false;
        //根據(jù)類型忽略相關(guān)的實(shí)現(xiàn)
        this.ignoredDependencyTypes = new HashSet();
        //忽略相關(guān)接口
        this.ignoredDependencyInterfaces = new HashSet();
        //  當(dāng)前創(chuàng)建的bean的名稱,用于隱式依賴項(xiàng)注冊(cè)
        //  從用戶指定的Supplier回調(diào)觸發(fā)的getBean等調(diào)用上
        this.currentlyCreatedBean = new NamedThreadLocal("Currently created bean");
        //未完成的FactoryBean實(shí)例的緩存:BeanWrapper的FactoryBean名稱
        this.factoryBeanInstanceCache = new ConcurrentHashMap();
        //按工廠類別緩存候選工廠方法
        this.factoryMethodCandidateCache = new ConcurrentHashMap();
       //過濾后的PropertyDescriptor的緩存:Bean類到PropertyDescriptor數(shù)組蝇闭。
        this.filteredPropertyDescriptorsCache = new ConcurrentHashMap();
        this.ignoreDependencyInterface(BeanNameAware.class);
        this.ignoreDependencyInterface(BeanFactoryAware.class);
        this.ignoreDependencyInterface(BeanClassLoaderAware.class);
    }

源碼中初始化了bean的代理模式呻率、bean循環(huán)依賴處理配置,以及緩存bean的相關(guān)工廠信息呻引。
最后忽略了BeanNameAware礼仗、BeanFactoryAwareBeanClassLoaderAware三個(gè)接口的相關(guān)類苞七。

暫時(shí)原因并不清楚藐守,為何要排除挪丢。這里暫時(shí)先不說蹂风,等說道bean加載的時(shí)候在說。

小結(jié)

本文主要講解了上下文構(gòu)建類的初始化過程乾蓬,到此仍在進(jìn)行bean加載前的準(zhǔn)備工作惠啄。上篇文章中初始化的環(huán)境對(duì)象被注入到上限文類中,繼續(xù)推進(jìn)初始化流程。

本文主要幾點(diǎn):
1.資源類注解@Resouce撵渡、@Value等融柬,背后的支持類初始化完成。
2.bean加載相關(guān)注解趋距,@Component粒氧、@Service,背后的支持類初始化节腐。
3.基于condition的條件注入
4.DefaultListableBeanFactory工廠類的初始化外盯。所謂IOC容器也是在這里進(jìn)行初始化。且內(nèi)部涉及到bean的循環(huán)依賴配置翼雀。

存留問題:
1.為何要在工廠類初始化的時(shí)候饱苟,移除BeanNameAwareBeanFactoryAware 狼渊、 BeanClassLoaderAware三個(gè)接口的加載箱熬?
2.spring如何解決循環(huán)依賴的問題
3.未完成的bean是如何保存的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市狈邑,隨后出現(xiàn)的幾起案子城须,更是在濱河造成了極大的恐慌,老刑警劉巖米苹,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酿傍,死亡現(xiàn)場離奇詭異,居然都是意外死亡驱入,警方通過查閱死者的電腦和手機(jī)赤炒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亏较,“玉大人莺褒,你說我怎么就攤上這事⊙┣椋” “怎么了遵岩?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長巡通。 經(jīng)常有香客問我尘执,道長,這世上最難降的妖魔是什么宴凉? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任誊锭,我火速辦了婚禮,結(jié)果婚禮上弥锄,老公的妹妹穿的比我還像新娘丧靡。我一直安慰自己蟆沫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布温治。 她就那樣靜靜地躺著饭庞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熬荆。 梳的紋絲不亂的頭發(fā)上舟山,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音卤恳,去河邊找鬼捏顺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛纬黎,可吹牛的內(nèi)容都是我干的幅骄。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼本今,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼拆座!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起冠息,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤挪凑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后逛艰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躏碳,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年散怖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菇绵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镇眷,死狀恐怖咬最,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欠动,我是刑警寧澤永乌,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站具伍,受9級(jí)特大地震影響翅雏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜人芽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一望几、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啼肩,春花似錦橄妆、人聲如沸衙伶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赦拘,卻和暖如春慌随,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躺同。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工阁猜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蹋艺。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓剃袍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捎谨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子民效,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容