真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

SpringbootCode的啟動(dòng)源碼是怎樣的

Springboot Code的啟動(dòng)源碼是怎樣的,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

創(chuàng)新互聯(lián)是專業(yè)的廣水網(wǎng)站建設(shè)公司,廣水接單;提供網(wǎng)站制作、成都做網(wǎng)站,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行廣水網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!

項(xiàng)目啟動(dòng)的流程:

(一)new SpringApplication

  1. 配置source和web環(huán)境;

  2. 創(chuàng)建初始化構(gòu)造器和應(yīng)用監(jiān)聽器;

  3. 配置應(yīng)用的主方法所在類;

(二)run 第一二部分

1.獲取并啟動(dòng)監(jiān)聽器

  • 初始化計(jì)時(shí)stopWatch、啟動(dòng)上下文bootstrapContext、設(shè)置系統(tǒng)參數(shù)headless;

  • 初始化監(jiān)聽器列表SpringApplicationRunListeners;

  • 發(fā)布springboot開始啟動(dòng)事件(從applicationListeners中過濾出4個(gè)能監(jiān)聽ApplicationStartingEvent事件的,并啟動(dòng)它們)

2.準(zhǔn)備環(huán)境

  • 裝配命令行參數(shù)applicationArguments(對(duì)象中裝載4個(gè)propertySource);

  • 準(zhǔn)備應(yīng)用程序運(yùn)行的環(huán)境ConfigurableEnvironment(從applicationListeners中過濾出6個(gè)能監(jiān)聽ApplicationEnvironmentPreparedEvent事件的,并啟動(dòng)它們。監(jiān)聽器中關(guān)聯(lián)啟動(dòng)了一些后置處理器處理數(shù)據(jù),最終目的是為應(yīng)用環(huán)境做準(zhǔn)備)

3.打印banner

方法:

     public ConfigurableApplicationContext run(String... args) {
        //1、StopWatch簡(jiǎn)單的看成一個(gè)stop watch的機(jī)制,保存stop的記錄信息。
        //初始化一個(gè)計(jì)時(shí)器,并開始計(jì)時(shí)
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        //初始化啟動(dòng)上下文
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        
        //2、configureHeadlessProperty即配置headless模式,這種模式是一種系統(tǒng)缺少顯示設(shè)備、鍵盤和鼠標(biāo)外設(shè)的情況模式。
        this.configureHeadlessProperty();

        //3、SpringApplicationListeners為SpringApplicationRunListener接口實(shí)現(xiàn)集合(創(chuàng)建SpringApplicationRunListener初始化構(gòu)造器)初始化監(jiān)聽器列表
        //可以理解這個(gè)接口就是在spring啟動(dòng)整個(gè)過程都需要回調(diào)這些listener
        //debug能發(fā)現(xiàn),拿到了一個(gè)名為EventPublishingRunListener(RunListener構(gòu)造方法中關(guān)聯(lián)上了全部applicationListener),這個(gè)就是用來進(jìn)行觸發(fā)publishEvent的被觀察者
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //啟動(dòng)EventPublishingRunListener,從而過濾并啟動(dòng)相關(guān)Listener
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //4、ConfigurableEnvironment為配置環(huán)境對(duì)象,簡(jiǎn)單理解所有的配置信息匯總在這個(gè)對(duì)象中
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);

            //5、Banner就是我們常在控制臺(tái)輸出的畫面橫幅,可以使用圖片或者文本進(jìn)行替換
            Banner printedBanner = this.printBanner(environment);

    =====>  //6、ConfigurableApplicationContext根據(jù)webApp…Type進(jìn)行構(gòu)造的上下文對(duì)象
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);

            //7、接下來進(jìn)入關(guān)鍵步驟的第一步:prepareContext,準(zhǔn)備容器階段,將執(zhí)行所有的initializers邏輯,做初始化準(zhǔn)備操作。
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

            //8、refreshContext,可以理解成容器初始化節(jié)點(diǎn),將執(zhí)行bean的創(chuàng)建和實(shí)例化。
            this.refreshContext(context);

            //9、afterRefresh,容器后處理, 可以看到會(huì)找到ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類并執(zhí)行。但從2.x版本來看,似乎這個(gè)方法是個(gè)空方法,applicationRun和commandRun移到啟動(dòng)最后。
            this.afterRefresh(context, applicationArguments);

            //10、然后根據(jù)stopwatch打印出啟動(dòng)時(shí)間
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
             
            //11、這里調(diào)用ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

下面開始對(duì)context的創(chuàng)建與準(zhǔn)備

    context = this.createApplicationContext();

    protected ConfigurableApplicationContext createApplicationContext() {
        return this.applicationContextFactory.create(this.webApplicationType);
    }
public interface ApplicationContextFactory {
    ApplicationContextFactory DEFAULT = (webApplicationType) -> {
        try {
            switch(webApplicationType) {
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                return new AnnotationConfigApplicationContext();
            }
        } catch (Exception var2) {
            throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
        }
    };

    ConfigurableApplicationContext create(WebApplicationType webApplicationType);
    ....
}

上述代碼可以通過webApplicationTyep(即SERVLET)創(chuàng)建 AnnotationConfigServletWebServerApplicationContext 對(duì)象,對(duì)象創(chuàng)建過程中,初始化了父類的屬性值,其中有三個(gè)比較關(guān)鍵的值,reader、scanner和父類中的beanFactory,下面這個(gè)對(duì)象的層級(jí)結(jié)構(gòu)需要了解一下

Springboot Code的啟動(dòng)源碼是怎樣的

/**
 * reader 和 scanner 都是在構(gòu)造方法中進(jìn)行了賦值
**/
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
    private final AnnotatedBeanDefinitionReader reader;
    private final ClassPathBeanDefinitionScanner scanner;
    private final Set> annotatedClasses;
    private String[] basePackages;

    public AnnotationConfigServletWebServerApplicationContext() {
        this.annotatedClasses = new LinkedHashSet();
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
    ...
}

我們可以在 GenericApplicationContext 類的構(gòu)造方法中看到其構(gòu)造方法中,對(duì)beanFactory屬性的賦值

    public GenericApplicationContext() {
        this.customClassLoader = false;
        this.refreshed = new AtomicBoolean();
        this.beanFactory = new DefaultListableBeanFactory();
    }

接下來對(duì)context進(jìn)行配置與準(zhǔn)備,看下prepareContext方法

//6、ConfigurableApplicationContext根據(jù)webApp…Type進(jìn)行構(gòu)造的上下文對(duì)象
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);

    =====>  //7、接下來進(jìn)入關(guān)鍵步驟的第一步:prepareContext,準(zhǔn)備容器階段,將執(zhí)行所有的initializers邏輯,做初始化準(zhǔn)備操作。
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

            //8、refreshContext,可以理解成容器初始化節(jié)點(diǎn),將執(zhí)行bean的創(chuàng)建和實(shí)例化。
            this.refreshContext(context);

            //9、afterRefresh,容器后處理, 可以看到會(huì)找到ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類并執(zhí)行。但從2.x版本來看,似乎這個(gè)方法是個(gè)空方法,applicationRun和commandRun移到啟動(dòng)最后。
            this.afterRefresh(context, applicationArguments);

            //10、然后根據(jù)stopwatch打印出啟動(dòng)時(shí)間
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
             
            //11、這里調(diào)用ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類
            this.callRunners(context, applicationArguments);
	/**
	 * Spring容器準(zhǔn)備
	 */
	private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
								ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
								ApplicationArguments applicationArguments, Banner printedBanner) {
		// 設(shè)置上下文環(huán)境
		context.setEnvironment(environment);
		//
		postProcessApplicationContext(context);
		// 執(zhí)行所有ApplicationContextInitializer對(duì)象的initialize方法(這些對(duì)象是通過讀取spring.factories加載)
		applyInitializers(context);
		// 發(fā)布上下文準(zhǔn)備完成事件到所有監(jiān)聽器
		listeners.contextPrepared(context);
		bootstrapContext.close(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		//
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 加載bean到上下文
		load(context, sources.toArray(new Object[0]));
		// 發(fā)送上下文加載完成事件
		listeners.contextLoaded(context);
	}



    //為context設(shè)置beanFactoryPostProcess
    protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        if (this.beanNameGenerator != null) {
            context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", this.beanNameGenerator);
        }

        if (this.resourceLoader != null) {
            if (context instanceof GenericApplicationContext) {
                ((GenericApplicationContext)context).setResourceLoader(this.resourceLoader);
            }

            if (context instanceof DefaultResourceLoader) {
                ((DefaultResourceLoader)context).setClassLoader(this.resourceLoader.getClassLoader());
            }
        }

        if (this.addConversionService) {
            context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
        }

    }

    //調(diào)用全部的構(gòu)造器
    protected void applyInitializers(ConfigurableApplicationContext context) {
        Iterator var2 = this.getInitializers().iterator();

        while(var2.hasNext()) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
            Class requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }

    }

    //加載class com.learning.demo.DemoApplication 啟動(dòng)類
    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }

        BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }

        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }

        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }

        loader.load();
    }

debug,此處load方法可以跟進(jìn)多層到 AnnotatedBeanDefinitionReader 的 registerBean(啟動(dòng)類)

    public void registerBean(Class beanClass) {
        this.doRegisterBean(beanClass, (String)null, (Class[])null, (Supplier)null, (BeanDefinitionCustomizer[])null);
    }

這里同樣有兩個(gè)listeners.*的兩個(gè)方法,和前面listeners.starting()是一樣的,提供下最近整理的類圖(了解Runlistener和listener類之間的關(guān)系)

Springboot Code的啟動(dòng)源碼是怎樣的

//6、ConfigurableApplicationContext根據(jù)webApp…Type進(jìn)行構(gòu)造的上下文對(duì)象
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);

            //7、接下來進(jìn)入關(guān)鍵步驟的第一步:prepareContext,準(zhǔn)備容器階段,將執(zhí)行所有的initializers邏輯,做初始化準(zhǔn)備操作。
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

     =====> //8、refreshContext,可以理解成容器初始化節(jié)點(diǎn),將執(zhí)行bean的創(chuàng)建和實(shí)例化。
            this.refreshContext(context);

            //9、afterRefresh,容器后處理, 可以看到會(huì)找到ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類并執(zhí)行。但從2.x版本來看,似乎這個(gè)方法是個(gè)空方法,applicationRun和commandRun移到啟動(dòng)最后。
            this.afterRefresh(context, applicationArguments);

            //10、然后根據(jù)stopwatch打印出啟動(dòng)時(shí)間
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
             
            //11、這里調(diào)用ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類
            this.callRunners(context, applicationArguments);

refreshContext() 是整個(gè)Run方法的核心部分

	/**
	 * 刷新應(yīng)用程序上下文
	 *
	 * @param context
	 */
	private void refreshContext(ConfigurableApplicationContext context) {
		// 注冊(cè)一個(gè)關(guān)閉鉤子,在jvm停止時(shí)會(huì)觸發(fā),然后退出時(shí)執(zhí)行一定的退出邏輯
		if (this.registerShutdownHook) {
			try {
				// 添加:Runtime.getRuntime().addShutdownHook()
				// 移除:Runtime.getRuntime().removeShutdownHook(this.shutdownHook)
				context.registerShutdownHook();
			} catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
		// ApplicationContext真正開始初始化容器和創(chuàng)建bean的階段
		refresh((ApplicationContext) context);
	}
	
	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
		refresh((ConfigurableApplicationContext) applicationContext);
	}

	protected void refresh(ConfigurableApplicationContext applicationContext) {
		applicationContext.refresh();
	}

調(diào)用應(yīng)用上下文對(duì)象的refresh()方法,接下來我i門到ConfigurableApplicationContext類中去看下這個(gè)方法

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
	void refresh() throws BeansException, IllegalStateException;
}

這是一個(gè)接口,且這個(gè)類是在spring框架中,非springboot,它的實(shí)現(xiàn)類共有三個(gè)

Springboot Code的啟動(dòng)源碼是怎樣的

AbstractApplicationContext是一個(gè)抽象類,其余兩個(gè)類都繼承了它,我們來看看這個(gè)抽象類的代碼:

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// 第一步:準(zhǔn)備更新上下時(shí)的預(yù)備工作
			prepareRefresh();

			// 第二步:獲取上下文內(nèi)部BeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 第三步:對(duì)BeanFactory做預(yù)備工作
			prepareBeanFactory(beanFactory);

			try {
				// 第四步:允許在上下文子類中對(duì)bean工廠進(jìn)行post-processing
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// 第五步:調(diào)用上下文中注冊(cè)為bean的工廠 BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// 第六步:注冊(cè)攔截bean創(chuàng)建的攔截器
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// 第七步:初始化MessageSource(國(guó)際化相關(guān))
				initMessageSource();

				// 第八步:初始化容器事件廣播器(用來發(fā)布事件)
				initApplicationEventMulticaster();

				// 第九步:初始化一些特殊的bean
				onRefresh();

				// 第十步:將所有監(jiān)聽器注冊(cè)到前兩步創(chuàng)建的事件廣播器中
				registerListeners();

				// 第十一步:結(jié)束bean的初始化工作(主要將所有單例BeanDefinition實(shí)例化)
				finishBeanFactoryInitialization(beanFactory);

				// 第十二步:afterRefresh(上下文刷新完畢,發(fā)布相應(yīng)事件)
				finishRefresh();
			} catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			} finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

這里有非常多的步驟,上下文對(duì)象主要的bean也是在這里進(jìn)行處理的,具體的說明可以看注釋, fresh方法就是SpringFrameWork的那部分(不再細(xì)化)

//6、ConfigurableApplicationContext根據(jù)webApp…Type進(jìn)行構(gòu)造的上下文對(duì)象
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);

            //7、接下來進(jìn)入關(guān)鍵步驟的第一步:prepareContext,準(zhǔn)備容器階段,將執(zhí)行所有的initializers邏輯,做初始化準(zhǔn)備操作。
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

            //8、refreshContext,可以理解成容器初始化節(jié)點(diǎn),將執(zhí)行bean的創(chuàng)建和實(shí)例化。
            this.refreshContext(context);

     =====> //9、afterRefresh,容器后處理, 可以看到會(huì)找到ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類并執(zhí)行。但從2.x版本來看,似乎這個(gè)方法是個(gè)空方法,applicationRun和commandRun移到啟動(dòng)最后。
            this.afterRefresh(context, applicationArguments);
     =====> //10、然后根據(jù)stopwatch打印出啟動(dòng)時(shí)間
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
             
            //11、這里調(diào)用ApplicationRunner和CommandLineRunner的實(shí)現(xiàn)類
            this.callRunners(context, applicationArguments);

afterRefresh() 是對(duì)方法 refresh() 的擴(kuò)展,暫時(shí)空方法。

stopWatch.stop() 根據(jù)stopwatch打印出啟動(dòng)時(shí)間,至此項(xiàng)目已經(jīng)啟動(dòng)完成。

* run方法主要做如下幾件事情:

  1. 發(fā)出啟動(dòng)結(jié)束事件

  2. 執(zhí)行實(shí)現(xiàn)ApplicationRunner、CommandLineRunner的run方法

  3. 發(fā)布應(yīng)用程序已啟動(dòng)(ApplicationStartedEvent)事件

結(jié)合網(wǎng)上共享的兩張圖可以清晰回顧下整體流程:

Springboot Code的啟動(dòng)源碼是怎樣的

Springboot Code的啟動(dòng)源碼是怎樣的

關(guān)于Springboot Code的啟動(dòng)源碼是怎樣的問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。


標(biāo)題名稱:SpringbootCode的啟動(dòng)源碼是怎樣的
轉(zhuǎn)載源于:http://weahome.cn/article/gscghc.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部