【二】SpringBoot源码分析之启动主流程----SpringApplication的run方法

一、简介

上一篇说了SpringApplication的创建,这一篇说run方法,关于IOC容器、BeanFactory、ServletContainer的创建和启动、Bean的注册和实例化都在run方法中。

调试源码的时候注意:

ApplicationContext为常说的Spring容器、IOC容器、应用上下文、Spring上下文。

ApplicationContext中有BeanFactory。

注意BeanPostProcessor和BeanFactoryPostProcessor的区别!

debug调式SpringBoot 1.5.8的源码,运行在tomcat上。

Spring Boot 通过扫描classpath下的实例决定装载哪个web容器。

我这里pom.xml文件用的spring-boot-starter-web所以,会启动tomcat来作为servlet的容器。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

整个启动流程图:

二、SpringApplication的实例创建好后调用run方法

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
        //开始计时(初始化需要花费多少时间)
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;

        //配置headless
		configureHeadlessProperty();

        //实现类只有EventPublishingRunListener
        //通过SpringApplicationRunListeners广播
		SpringApplicationRunListeners listeners = getRunListeners(args);

        //收到广播的类执行相应的操作
		listeners.starting();
		try {
            // 构造一个应用程序参数持有类
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);

            // 配置环境模,这里面ConfigFileApplicationListener接收到事件后会调用postProcessEnvironment方法加载application.yml配置文件

			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);

            //配置Banner
			Banner printedBanner = printBanner(environment);

            // 创建Spring的ApplicationContext
            //class org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
			context = createApplicationContext();
			analyzers = new FailureAnalyzers(context);

            //这里面会执行所有的初始化器Initializer的逻辑
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);

            //执行bean的创建和实例化
			refreshContext(context);

			afterRefresh(context, applicationArguments);

            // 广播出ApplicationReadyEvent事件给相应的监听器执行
			listeners.finished(context, null);

            //计时结束
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}

run方法主要做的事有:

1.stopWatch.start()

开始计时初始化需要花费多少时间

源码

	public void start(String taskName) throws IllegalStateException {
		if (this.running) {
			throw new IllegalStateException("Can't start StopWatch: it's already running");
		}
		this.running = true;
		this.currentTaskName = taskName;
		this.startTimeMillis = System.currentTimeMillis();
	}

2.Headless配置

configureHeadlessProperty();
	private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
				SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

3.创建SpringApplicationRunListeners,发送事件广播

SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener

这里listeners.starting()发送了ApplicationStartedEvent广播。

		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

 SpringApplicationRunListenesr类有5个方法,发送了不同的事件:

方法何时调用对应事件
startingrun方法执行时就调用ApplicationStartedEvent
environmentPreparedApplicationContext创建之前并且环境信息准备好的时候调用ApplicationEnvironmentPreparedEvent
contextPreparedApplicationContext创建好并且在source加载之前调用一次无,实现类EventPublishingRunListener中该方法为空的
contextLoadedApplicationContext创建并加载之后并在refresh之前调用ApplicationPreparedEvent
finishedrun方法结束之前调用ApplicationReadyEvent或ApplicationFailedEvent

监听器收到 ApplicationStartedEvent事件广播后执行的逻辑:

3.1 LoggingApplicationListener处理ApplicationStartedEvent事件

源码

	private void onApplicationStartingEvent(ApplicationStartingEvent event) {
		this.loggingSystem = LoggingSystem
				.get(event.getSpringApplication().getClassLoader());
		this.loggingSystem.beforeInitialize();
	}

初始化日志系统

3.2 BackgroundPreinitializer处理ApplicationStartedEvent事件

 无,该监听器并没有监听该事件

3.3 DelegatingApplicationListener处理ApplicationStartedEvent事件

无,没有监听该事件

3.4 LiquibaseServiceLocatorApplicationListener处理ApplicationStartedEvent事件

源码

	public void onApplicationEvent(ApplicationStartingEvent event) {
		if (ClassUtils.isPresent("liquibase.servicelocator.ServiceLocator", null)) {
			new LiquibasePresent().replaceServiceLocator();
		}
	}

无,并没有走到判断条件中 

4.配置环境模块prepareEnvironment

配置一些环境信息。

ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);

源码

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// 创建应用程序的环境信息。如果是web程序,创建StandardServletEnvironment;否则,创建StandardEnvironment
		ConfigurableEnvironment environment = getOrCreateEnvironment();

        // 配置一些环境信息。比如profile,命令行参数
		configureEnvironment(environment, applicationArguments.getSourceArgs());

        // 广播出ApplicationEnvironmentPreparedEvent事件给相应的监听器执行
		listeners.environmentPrepared(environment);
 
        // 环境信息的校对  这里是true,并不会走if里面
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		return environment;
	}

做了4件事

4.1创建应用程序的环境信息。

如果是web程序,创建StandardServletEnvironment;否则,创建StandardEnvironment。

4.2配置一些环境信息。比如profile,命令行参数。

4.3广播出ApplicationEnvironmentPreparedEvent事件给相应的监听器

监听器收到 ApplicationEnvironmentPreparedEvent事件广播后执行的逻辑:

4.3.1 ConfigFileApplicationListener处理ApplicationEnvironmentPreparedEvent事件

源码

	private void onApplicationEnvironmentPreparedEvent(
			ApplicationEnvironmentPreparedEvent event) {

        // 1.读取spring.factories文件,加载环境后置处理器
		List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();

        // 2.把ConfigFileApplicationListener监听器也加入到环境后置处理器中
		postProcessors.add(this);

        // 3.排序
		AnnotationAwareOrderComparator.sort(postProcessors);

        // 4.执行每个PostProcessors后置处理环境的逻辑
		for (EnvironmentPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessEnvironment(event.getEnvironment(),
					event.getSpringApplication());
		}
	}

做了4件事 

1.读取spring.factories文件,加载环境后置处理器(SpringApplicationJsonEnvironmentPostProcessorCloudFoundryVcapEnvironmentPostProcessor

2.把ConfigFileApplicationListener监听器也加入到环境后置处理器中

3.排序

4.执行每个PostProcessors后置处理环境的逻辑

其中,后置处理器及其执行逻辑:

SpringApplicationJsonEnvironmentPostProcessor源码:并没有走到if里面去,相当于什么都没做。

@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment,
			SpringApplication application) {
		String json = environment.resolvePlaceholders(
				"${spring.application.json:${SPRING_APPLICATION_JSON:}}");
		if (StringUtils.hasText(json)) {
			processJson(environment, json);
		}
	}

 CloudFoundryVcapEnvironmentPostProcessor源码:并没有走到if里面去,相当于什么都没做

public void postProcessEnvironment(ConfigurableEnvironment environment,
			SpringApplication application) {
		if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {
			Properties properties = new Properties();
			addWithPrefix(properties, getPropertiesFromApplication(environment),
					"vcap.application.");
			addWithPrefix(properties, getPropertiesFromServices(environment),
					"vcap.services.");
			MutablePropertySources propertySources = environment.getPropertySources();
			if (propertySources.contains(
					CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
				propertySources.addAfter(
						CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
						new PropertiesPropertySource("vcap", properties));
			}
			else {
				propertySources
						.addFirst(new PropertiesPropertySource("vcap", properties));
			}
		}
	}

ConfigFileApplicationListener源码:

	public void postProcessEnvironment(ConfigurableEnvironment environment,
			SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
		configureIgnoreBeanInfo(environment);
		bindToSpringApplication(environment, application);
	}

关于ConfigFileApplicationListener,考虑另外专门写一篇来介绍

【九】Spring Boot 源码分析之启动主流程----ConfigFileApplicationListener的postProcessEnvironment方法

4.4环境信息的校对

源码:这里是true,并不会走if里面。

        // 环境信息的校对  这里是true,并不会走if里面
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}

5.配置Banner

是否在控制台上打印自定义的banner

Banner printedBanner = printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
				: new DefaultResourceLoader(getClassLoader());
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
				resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

控制台的这个图像就是打印出来的Banner

6.创建spring容器 ApplicationContext

这里实际创建的容器是AnnotationConfigEmbeddedWebApplicationContext

WebApplicationContext有两个核心实现,一个就是AnnotationConfigEmbeddedWebApplicationContext,用@Configuration配置方式装载类。另一个是XmlWebApplicationContext,用XML配置文件方式装载类

context = createApplicationContext();

源码

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {

                // 如果是web程序,那么构造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器
                // 否则构造org.springframework.context.annotation.AnnotationConfigApplicationContext容器
				contextClass = Class.forName(this.webEnvironment
						? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}

如果是web程序,那么构造org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext容器 ,否则构造org.springframework.context.annotation.AnnotationConfigApplicationContext容器。

在BeanUtils.instantiate方法中用反射创建ApplicationContext的时候会把容器需要的BeanFactory也一起创建了。

7.为刷新spring容器做准备

prepareContext(context, environment, listeners, applicationArguments,printedBanner);

源码

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {

        // 设置Spring容器的环境信息
		context.setEnvironment(environment);

         // 回调方法,Spring容器创建之后做一些额外的事
		postProcessApplicationContext(context);

        // SpringApplication的的初始化器开始工作
		applyInitializers(context);

        // 遍历调用SpringApplicationRunListener的contextPrepared方法。目前只是将这个事件广播器注册到Spring容器中
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// 把应用程序参数持有类注册到Spring容器中,并且是一个单例
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
		Set<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));

        // 广播出ApplicationPreparedEvent事件给相应的监听器执行
		listeners.contextLoaded(context);
	}

专门另外写一篇来详细介绍 SpringApplication类的prepareContext方法

【三】Spring Boot 源码分析之启动主流程---SpringApplication的prepareContext方法

8.刷新spring容器 ApplicationContext

refreshContext(context);
	private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}

 

	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}

 里面最终调用的是AbstractApplicationContext类的refresh方法来刷新容器

源码:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {

			//设置Spring容器的启动时间,撤销关闭状态,开启活跃状态。
            //初始化属性源信息
            //验证环境信息里一些必须存在的属性
			prepareRefresh();

			//调用子类的refeshBeanFactory(),SpringBoot中采用默认的实现,设置BeanFactory的SerializationId,设置refreshed标志为true。
            //获取BeanFactory
            //XmlWebApplicationContext ,AnnotationConfigApplicationContext 会在这一步加载BeanDefinition
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			//设置classloader用于加载bean,设置表达式解析器,设置资源编辑注册器
            //添加ApplicationContextAwareProcessor这个BeanPostProcessor。取消ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware这5个接口的自动注入。因为ApplicationContextAwareProcessor把这5个接口的实现工作做了
            //注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去。ResourceLoader、ApplicationEventPublisher、ApplicationContext这3个接口对应的bean都设置为当前的Spring容器
            //注入一些其它信息的bean,比如environment、systemProperties等 
			prepareBeanFactory(beanFactory);

			try {

				//给beanFactory添加后置处理器WebApplicationContextServletContextAwareProcessor
				postProcessBeanFactory(beanFactory);

				//激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
                //把BeanDefinition都注册到容器的注册表(一个Map)中,先注册PriorityOrdered,再注册Ordered,再注册nonOrdered的
				invokeBeanFactoryPostProcessors(beanFactory);

				//注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor。
				registerBeanPostProcessors(beanFactory);

				//初始化上下文中的资源文件,如国际化文件的处理等
				initMessageSource();

				//在Spring容器中初始化事件广播器,事件广播器用于事件的发布。
				initApplicationEventMulticaster();

				// 该方法中会去创建内嵌的Servlet容器,这里既是Tomcat。

                //跟到里面会发现启动了Tomcat的Server、Service、Engine、Realm、Pipeline、Value、MapperListerner
				onRefresh();

				//把Spring容器内的时间监听器和BeanFactory中的时间监听器都添加的事件广播器中,并且广播出去。
				registerListeners();

				// 实例化BeanFactory中已经被注册但是未实例化的所有实例(懒加载的不需要实例化)。即生成环境所需要的Bean。
				finishBeanFactoryInitialization(beanFactory);

				// 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法
                // 启动Tomcat中所有实现Lifecycle接口的组件
                //通过spring的事件发布机制发布ContextRefreshedEvent事件。
				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();
			}
		}
	}

专门另外写一篇来详细介绍 AbstractApplicationContext类的refresh方法

【四】Spring Boot 源码分析之启动主流程---AbstractApplicationContext的refresh方法

9.  afterRefresh方法

实际上是调用了SpringApplication类的callRunners()方法

源码:

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<Object>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<Object>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

从ApplicationContext容器中拿出ApplicationRunner和CommandLineRunner的bean,调用他们每个的run方法。

这里debug的时候由于没有Runner,就直接跳过了。

10.广播

listeners.finished(context, null);

 这里跟进去是调用SpringApplication实例中的EventPublishingRunListenerfinished方法。

源码:

public void finished(ConfigurableApplicationContext context, Throwable exception) {

        // 如果启动中没有抛出异常,则发布ApplicationReadyEvent事件,有抛出异常则发布ApplicationFailedEvent事件。
		SpringApplicationEvent event = getFinishedEvent(context, exception);
		if (context != null && context.isActive()) {
			// Listeners have been registered to the application context so we should
			// use it at this point if we can
			context.publishEvent(event);
		}
		else {
			// An inactive context may not have a multicaster so we use our multicaster to
			// call all of the context's listeners instead
			if (context instanceof AbstractApplicationContext) {
				for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
						.getApplicationListeners()) {
					this.initialMulticaster.addApplicationListener(listener);
				}
			}
			if (event instanceof ApplicationFailedEvent) {
				this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
			}
			this.initialMulticaster.multicastEvent(event);
		}
	}

如果启动中没有抛出异常,则发布ApplicationReadyEvent事件,有抛出异常则发布ApplicationFailedEvent事件。

使用ApplicationContext中的SimpleApplicationEventMulticaster发布事件。

下面详细介绍哪些该事件会发布给哪些监听器,以及监听器执行的逻辑

10.1 BackgroundPreinitializer

源码:一个CountDownLatch调用await()等待

public void onApplicationEvent(SpringApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			if (preinitializationStarted.compareAndSet(false, true)) {
				performPreinitialization();
			}
		}
		if ((event instanceof ApplicationReadyEvent
				|| event instanceof ApplicationFailedEvent)
				&& preinitializationStarted.get()) {
			try {
				preinitializationComplete.await();
			}
			catch (InterruptedException ex) {
				Thread.currentThread().interrupt();
			}
		}
	}

10.2 DelegatingApplicationListener

 源码:并没有监听ApplicationReadyEvent事件,并且muiticaster为空,等于什么都没做。

	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
					((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
			if (delegates.isEmpty()) {
				return;
			}
			this.multicaster = new SimpleApplicationEventMulticaster();
			for (ApplicationListener<ApplicationEvent> listener : delegates) {
				this.multicaster.addApplicationListener(listener);
			}
		}
		if (this.multicaster != null) {
			this.multicaster.multicastEvent(event);
		}
	}

10.3 SpringApplicationAdminMXBeanRegistrar

 源码:修改flag

	public void onApplicationEvent(ApplicationReadyEvent event) {
		if (this.applicationContext.equals(event.getApplicationContext())) {
			this.ready = true;
		}
	}

11.计时结束

stopWatch.stop();

源码

	public void stop() throws IllegalStateException {
		if (!this.running) {
			throw new IllegalStateException("Can't stop StopWatch: it's not running");
		}
		long lastTime = System.currentTimeMillis() - this.startTimeMillis;
		this.totalTimeMillis += lastTime;
		this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
		if (this.keepTaskList) {
			this.taskList.add(lastTaskInfo);
		}
		++this.taskCount;
		this.running = false;
		this.currentTaskName = null;
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值