spring之初始化上下文環(huán)境

本文的目的

  • 基于源碼快速的了解一個(gè)對(duì)象是怎么產(chǎn)生的
  • 我們可以怎么對(duì)spring的生產(chǎn)過(guò)程進(jìn)行干預(yù)

對(duì)象的一個(gè)大致創(chuàng)建流程

bean轉(zhuǎn)成bd放入到bdMap中宽涌,然后根據(jù)bean的名稱從bdMap中拿bd進(jìn)行創(chuàng)建炫加,創(chuàng)建的時(shí)候會(huì)經(jīng)過(guò)一系列的后置處理器,最中返回我們需要?jiǎng)?chuàng)建的bean
最后會(huì)總結(jié)出來(lái)一張圖來(lái)解釋

構(gòu)建測(cè)試用例

  • 代碼如下
@Test
    public void registerBean() {
       // 1  初始化上下文環(huán)境 AnnotationConfigApplicationContext 
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
       //2 添加配置類
        context.register(Config.class, NameConfig.class);
       //3 執(zhí)行工廠的刷新方法
        context.refresh();
       //4  調(diào)用getBean方法 獲取對(duì)象
        TestBean testBean = (TestBean) context.getBean("testBean");
        assertEquals("foo", testBean.name);
    }

    @Configuration
    static class Config {
        @Bean
        public TestBean testBean() {
            TestBean testBean = new TestBean();
            testBean.name = "foo";
            return testBean;
        }
    }

    @Configuration
    static class NameConfig {
        @Bean
        String name() {
            return "foo";
        }
    }

由于篇幅原因靶瘸,本章只解釋第一步驟 初始化上下文環(huán)境 AnnotationConfigApplicationContext

初始化上下文環(huán)境都做了一下什么事寝优?

當(dāng)執(zhí)行了 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();這行代碼条舔, 會(huì)執(zhí)行初始化的構(gòu)造方法;
根據(jù)繼承關(guān)系 AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry 可以看出乏矾,會(huì)先執(zhí)行 GenericApplicationContext的構(gòu)造方法孟抗,然后再執(zhí)行AnnotationConfigApplicationContext 的構(gòu)造方法

執(zhí)行GenericApplicationContext的構(gòu)造方法

    /**
     * 創(chuàng)建一個(gè) beanFactory
     * Create a new GenericApplicationContext.
     * @see #registerBeanDefinition
     * @see #refresh
     */
    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }

創(chuàng)建一個(gè) DefaultListableBeanFactory 對(duì)象

    /**
     * Create a new DefaultListableBeanFactory.
     */
    public DefaultListableBeanFactory() {
        super();
    }

super()方法中在父類的實(shí)現(xiàn)

    /**
     * Create a new AbstractAutowireCapableBeanFactory.
     */
    public AbstractAutowireCapableBeanFactory() {
        super();
        //添加忽略依賴的接口 BeanNameAware
        ignoreDependencyInterface(BeanNameAware.class);
       //添加忽略依賴的接口 BeanFactoryAware
        ignoreDependencyInterface(BeanFactoryAware.class);
        //添加忽略依賴的接口 BeanClassLoaderAware
        ignoreDependencyInterface(BeanClassLoaderAware.class);
    }

執(zhí)行完構(gòu)造方法后是創(chuàng)建了一個(gè)DefaultListableBeanFactory對(duì)象,對(duì)象包含很多屬性钻心,簡(jiǎn)要列舉下下邊會(huì)用到的屬性夸浅。

    /** key是bean的名稱value是BeanDefinition*/
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    /** bean名稱的集合 */
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
    /**bean的后置處理器*/
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

執(zhí)行AnnotationConfigApplicationContext本身的構(gòu)造方法

    /**
     * 創(chuàng)建注解配置類型的額上下文 本身也是一個(gè)注冊(cè)中心
     * 會(huì)調(diào)用父類方法    創(chuàng)建 beanFactory
     * Create a new AnnotationConfigApplicationContext that needs to be populated
     * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
     */
    public AnnotationConfigApplicationContext() {
        // 注解bean定義信息解析器
        // 添加工廠的后置處理器 和bean的后置處理器
        this.reader = new AnnotatedBeanDefinitionReader(this);
        //掃描指定包下的bean轉(zhuǎn)成bd
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

這個(gè)構(gòu)造方法很重要
首先是實(shí)例化一個(gè)AnnotatedBeanDefinitionReader對(duì)象,這個(gè)對(duì)象的作用就是解析被注解的bean扔役,轉(zhuǎn)換成beanDefinition帆喇;還有就是向容器中添加beanFactory的后置處理器和bean的后置處理器。注意這個(gè)構(gòu)造方法是需要傳入一個(gè) registry 亿胸,通過(guò)最開(kāi)始的繼承結(jié)構(gòu)可以知道AnnotationConfigApplicationContext 也實(shí)現(xiàn)了BeanDefinitionRegistry接口

創(chuàng)建ClassPathBeanDefinitionScanner對(duì)象坯钦,這個(gè)對(duì)象如果是采用的注解方式并且沒(méi)有手動(dòng)調(diào)用context.scan("org.springframework.context.xxx");這個(gè)方法實(shí)際上是沒(méi)有用的,看名稱我們可以知道侈玄,這個(gè)對(duì)象主要是掃描ClassPath下的bean轉(zhuǎn)換成BeanDefinition婉刀。但是實(shí)際在后邊真正處理的時(shí)候會(huì)重新新建一個(gè),在這次存在的意思就是類似與上邊我們手動(dòng)調(diào)用scan方法

所以接下來(lái)我們著重講解AnnotatedBeanDefinitionReader對(duì)象
當(dāng)我們調(diào)用這個(gè)對(duì)象的構(gòu)造方法的時(shí)候最終會(huì)進(jìn)入org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)這個(gè)方法
代碼如下

/**
     * Register all relevant annotation post processors in the given registry.
     *
     * @param registry the registry to operate on
     * @param source   the configuration source element (already extracted)
     *                 that this registration was triggered from. May be {@code null}.
     * @return a Set of BeanDefinitionHolders, containing all bean definitions
     * that have actually been registered by this call
     */
    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {
        //獲取 beanFactory  此處是 DefaultListableBeanFactory 看前邊的繼承關(guān)系
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                //添加 排序的bean
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                //用于確定特定的Bean定義是否符合特定的依賴項(xiàng)的候選者的策略接口序仙。
                //ContextAnnotationAutowireCandidateResolver這個(gè)是最全的一個(gè)策略接口可以處理Lazy
                //此處處理的lazy不是懶加載突颊,是懶處理
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }
        // BeanDefinitionHolder 是對(duì)  bd 和bean 名稱的一個(gè)封裝
        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
        //name=org.springframework.context.annotation.internalConfigurationAnnotationProcessor
        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //添加  BeanDefinitionRegistryPostProcessor 類型的實(shí)現(xiàn)類   ConfigurationClassPostProcessor 也是 beanFactoryPostProcessor的實(shí)現(xiàn)類
            // ConfigurationClassPostProcessor 這個(gè)類的作用很大 會(huì)把我們程序中需要加載的bean轉(zhuǎn)乘bd從而被實(shí)例化成bean
            //后邊會(huì)著重講解
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }
        //org.springframework.context.annotation.internalAutowiredAnnotationProcessor
        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //添加BeanPostProcessor類型的實(shí)現(xiàn)類 AutowiredAnnotationBeanPostProcessor  主要是解決屬性自動(dòng)裝配問(wèn)題
            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.
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            //添加BeanPostProcessor類型的實(shí)現(xiàn)類 CommonAnnotationBeanPostProcessor  主要是處理類中的  PreDestroy ,PostConstruct 潘悼,Resource 這些注解
            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.
        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));
        }

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

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

這個(gè)方法的主要主要作用就是向給定的注冊(cè)中心中加入beanFactory的后置處理器ConfigurationClassPostProcessor(會(huì)在refresh中重點(diǎn)講解)和一些bean的后置處理器比如 CommonAnnotationBeanPostProcessor主要負(fù)責(zé)處理類中的 PreDestroy 律秃,PostConstruct ,Resource 這些注解治唤。

執(zhí)行第二步向注冊(cè)中心添加配置類

代碼 context.register(Config.class, NameConfig.class);
方法最終調(diào)用 org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean

/**
     * Register a bean from the given bean class, deriving its metadata from
     * class-declared annotations.
     * @param beanClass the class of the bean
     * @param instanceSupplier a callback for creating an instance of the bean
     * (may be {@code null})
     * @param name an explicit name for the bean
     * @param qualifiers specific qualifier annotations to consider, if any,
     * in addition to qualifiers at the bean class level
     * @param definitionCustomizers one or more callbacks for customizing the
     * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
     * @since 5.0
     */
    <T> void doRegisterBean(Class<T> beanClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
        //傳進(jìn)來(lái)的類包裝成 AnnotatedGenericBeanDefinition 
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        //是否需要跳過(guò) 一般不會(huì) 
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }
        //注冊(cè)回到函數(shù)獲取對(duì)象 一般沒(méi)有
        abd.setInstanceSupplier(instanceSupplier);
        //解析作用域  如果沒(méi)有指定 默認(rèn)為單例 指定的化 根據(jù)注解上的信息獲取值
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        //設(shè)置作用域
        abd.setScope(scopeMetadata.getScopeName());
        //獲得一個(gè)bean的名稱
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
        //處理通用注解信息  Lazy Primary  DependsOn Role  Description 如果有這些屬性 則取出賦值
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        //qualifiers 類型的注解不為null的處理
        if (qualifiers != null) {
            for (Class<? extends Annotation> qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                }
                else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                }
                else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        //自定義函數(shù) 處理bd 一般沒(méi)有
        for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
            customizer.customize(abd);
        }
        //組裝成 definitionHolder 
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        //應(yīng)用 ScopedProxyMode  判斷需不需要生成代理  一般不會(huì)用  上邊默認(rèn)為 no 
        //@Scope(value = "prototype",proxyMode= ScopedProxyMode.TARGET_CLASS) 則每次調(diào)用時(shí)都會(huì)生成一個(gè)對(duì)象
        //@Scope(value = "prototype") 同一個(gè)session 多次調(diào)用 產(chǎn)生同一個(gè)對(duì)象 不同的session調(diào)用每次都產(chǎn)生新的對(duì)象
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        //放入到bdMap中
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

到現(xiàn)在位置構(gòu)造環(huán)境的前兩步就講完了棒动,下一篇文章主要講解org.springframework.context.support.AbstractApplicationContext#refresh方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市宾添,隨后出現(xiàn)的幾起案子船惨,更是在濱河造成了極大的恐慌柜裸,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粱锐,死亡現(xiàn)場(chǎng)離奇詭異疙挺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)怜浅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門铐然,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人海雪,你說(shuō)我怎么就攤上這事锦爵〔盏睿” “怎么了奥裸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沪袭。 經(jīng)常有香客問(wèn)我湾宙,道長(zhǎng),這世上最難降的妖魔是什么冈绊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任侠鳄,我火速辦了婚禮,結(jié)果婚禮上死宣,老公的妹妹穿的比我還像新娘伟恶。我一直安慰自己,他們只是感情好毅该,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布博秫。 她就那樣靜靜地躺著,像睡著了一般眶掌。 火紅的嫁衣襯著肌膚如雪挡育。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,792評(píng)論 1 290
  • 那天朴爬,我揣著相機(jī)與錄音即寒,去河邊找鬼。 笑死召噩,一個(gè)胖子當(dāng)著我的面吹牛母赵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播具滴,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼市咽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了抵蚊?” 一聲冷哼從身側(cè)響起施绎,我...
    開(kāi)封第一講書(shū)人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤溯革,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后谷醉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體致稀,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年俱尼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抖单。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遇八,死狀恐怖矛绘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刃永,我是刑警寧澤货矮,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站斯够,受9級(jí)特大地震影響囚玫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜读规,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一抓督、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧束亏,春花似錦铃在、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至雀久,卻和暖如春宿稀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赖捌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工祝沸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人越庇。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓罩锐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親卤唉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涩惑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348