springboot源碼走讀之三----context生成【 createApplicationContext】

前面的話

前面兩篇文章主要是走讀了springboot啟動(dòng)時(shí)的準(zhǔn)備階段,本文正式進(jìn)入重點(diǎn)的階段摇邦。即spring context的生成汞窗。即如下代碼:

//生成spring的context
    context = createApplicationContext();
// 異常上報(bào)
    exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);
//準(zhǔn)備spring context
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//組裝spring context,這一步是重點(diǎn)刊苍。主要是spring的機(jī)制
    refreshContext(context);

下面來(lái)分別走讀每行代碼既们。

createApplicationContext

createApplicationContext的代碼如下:

protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

根據(jù)不同的webType初始化不同的context。如果是servlet正什,則通過(guò)反射啥纸,初始化org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext,如果是reactive類型,則初始化org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext,如果都不是上面的類型婴氮,則初始化org.springframework.context.annotation.AnnotationConfigApplicationContext.
本文主要走讀servlet類型斯棒。下面主要看AnnotationConfigServletWebServerApplicationContext的類圖。

AnnotationConfigServletWebServerApplicationContext.png

這里看下初始化AnnotationConfigServletWebServerApplicationContext干了哪些事情主经。
由于該類繼承了GenericApplicationContext荣暮,GenericApplicationContext中的構(gòu)造方法里初始化了beanfactory。

    /**
     * Create a new GenericApplicationContext.
     * @see #registerBeanDefinition
     * @see #refresh
     */
    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }

這里直接new出一個(gè)DefaultListableBeanFactory出來(lái)旨怠。
AnnotationConfigServletWebServerApplicationContext的無(wú)參構(gòu)造方法里做了哪些事情呢渠驼?

    public AnnotationConfigServletWebServerApplicationContext() {
              //注解相關(guān)的處理
        this.reader = new AnnotatedBeanDefinitionReader(this);
              //scan相關(guān)處理
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

初始化reader和scanner。具體做的事情是什么呢鉴腻?
new AnnotatedBeanDefinitionReader(this);的代碼如下:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

代碼中this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);是注冊(cè)Conditional注解家族的處理類迷扇。Conditional注解主要作用是百揭,注冊(cè)滿足條件的bean,Conditional注解家族有如下成員:

Conditional注解成員

當(dāng)然蜓席,我們也可以自定義條件器一,只需要實(shí)現(xiàn)Condition接口。定義如下:

public interface Condition {

    /**
     * Determine if the condition matches.
     * @param context the condition context
     * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
     * or {@link org.springframework.core.type.MethodMetadata method} being checked
     * @return {@code true} if the condition matches and the component can be registered,
     * or {@code false} to veto the annotated component's registration
     */
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

然后在使用的時(shí)候厨内,在類或者方法上使用@Conditional(yourconditon.class)

代碼中AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);主要是實(shí)例化spring相關(guān)注解的bean祈秕。
代碼如下

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                              //@Order的處理bean
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                                //@Lazy,@Qualifier的處理bean
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

              //@Configuration 注解的bean注冊(cè)
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
                //@Autowired 和@Value注解的bean注冊(cè)雏胃。
        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            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.
                //java 自有注解的處理请毛,如@Resource,@PostConstruct瞭亮,@PreDestroy等
        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相關(guān)注解的處理
        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));
        }

                //@EventListener注解的處理
        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));
        }
                // 事件工廠的默認(rèn)實(shí)現(xià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;
    }

接下來(lái)方仿,走讀this.scanner = new ClassPathBeanDefinitionScanner(this);
代碼如下:

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
            Environment environment, @Nullable ResourceLoader resourceLoader) {

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        if (useDefaultFilters) {
            registerDefaultFilters();
        }
        setEnvironment(environment);
        setResourceLoader(resourceLoader);
    }

這段代碼主要是注冊(cè)掃描的默認(rèn)過(guò)濾規(guī)則,默認(rèn)規(guī)則掃描@Component ,@Repository,@Service,@Controller等及JAVAEE6的@ManagedBean和JSR-330的@Named统翩。
至此仙蚜,context的初始化算是告一段落了,總結(jié)下來(lái)厂汗,在初始化context時(shí)委粉,做了哪些事情呢?
1娶桦、通過(guò)webType贾节,獲取不同的context class,這里以servlet為例走讀趟紊。通過(guò)反射初始化AnnotationConfigServletWebServerApplicationContext
2氮双、在context例初始化beanFactory。new一個(gè)DefaultListableBeanFactory霎匈。
3、注冊(cè)bean的處理類送爸。如:conditional铛嘱,@order,@lazy袭厂,@autowared等注解的處理墨吓。
4、注冊(cè)掃描規(guī)則等纹磺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帖烘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子橄杨,更是在濱河造成了極大的恐慌秘症,老刑警劉巖照卦,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異乡摹,居然都是意外死亡役耕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門聪廉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瞬痘,“玉大人,你說(shuō)我怎么就攤上這事板熊】蛉” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵干签,是天一觀的道長(zhǎng)竣况。 經(jīng)常有香客問(wèn)我,道長(zhǎng)筒严,這世上最難降的妖魔是什么丹泉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮鸭蛙,結(jié)果婚禮上摹恨,老公的妹妹穿的比我還像新娘。我一直安慰自己娶视,他們只是感情好晒哄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著肪获,像睡著了一般寝凌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上孝赫,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天较木,我揣著相機(jī)與錄音,去河邊找鬼青柄。 笑死伐债,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的致开。 我是一名探鬼主播峰锁,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼双戳!你這毒婦竟也來(lái)了虹蒋?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎魄衅,沒(méi)想到半個(gè)月后峭竣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡徐绑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年邪驮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傲茄。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毅访,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盘榨,到底是詐尸還是另有隱情喻粹,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布草巡,位于F島的核電站守呜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏山憨。R本人自食惡果不足惜查乒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望郁竟。 院中可真熱鬧玛迄,春花似錦、人聲如沸棚亩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)讥蟆。三九已至勒虾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瘸彤,已是汗流浹背修然。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钧栖,地道東北人低零。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拯杠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子啃奴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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

  • 不知不覺(jué)潭陪,麻麻產(chǎn)假快休完的時(shí)候,你外婆問(wèn)麻麻:“你還要去上海啊依溯?寶寶還這么小老厌,就不能留在家里嗎?你們兩個(gè)帶...
    nikkicao閱讀 969評(píng)論 0 2
  • 那顆進(jìn)了鞋的小石子淀弹,后來(lái)怎樣了? 文|木槿 前幾天庆械,在家樓下薇溃,看到一個(gè)男的皺著眉,訓(xùn)斥著他老婆缭乘,說(shuō)的唾沫星子亂飛沐序,...
    木槿的角落閱讀 573評(píng)論 3 7
  • 愿沉睡花海,永遠(yuǎn)守候前世的記憶堕绩。 無(wú)邊的繁華凋落后的盛開(kāi)策幼,是接近永久的安息途中,最后一場(chǎng)盛宴奴紧。 穿透皮膚的刺特姐,糜爛...
    木衛(wèi)十閱讀 832評(píng)論 25 30