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

该方法主要是为刷新spring容器做准备

入口在SpringApplication类的run方法调用prepareContext方法,

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

做了这8件事

1.context.setEnvironment(environment)

设置ApplicationContext容器的环境Environment信息。

	public void setEnvironment(ConfigurableEnvironment environment) {
		super.setEnvironment(environment);
		this.reader.setEnvironment(environment);
		this.scanner.setEnvironment(environment);
	}

Environment有撒子?写个最简单的springboot项目打个断点看:

servletConfigInitParams  空嘞,没去搞这个

servletContextInitParams 空嘞,没去搞这个

systemProperties 多得很,大概是些撒子我截图

比如说撒子操作系统,file encoding,JDK的那些包呀路径呀在哪里的

 

systemEnvironment 这个就是系统环境变量

 

random

applicationConfigurationProperties 这个主要就是springboot里面自己写的那个application.yml中的内容

 

2.postProcessApplicationContext方法。

由于beanNameGenerator和resourceLoader此时为空,所以什么都没做。

源码:

	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			context.getBeanFactory().registerSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					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());
			}
		}
	}

3.applyInitializers方法

SpringApplication实例化的时候创建的那6个初始化器Initializer开始工作,调用他们每个初始化器的initialize方法。

protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
					initializer.getClass(), ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			initializer.initialize(context);
		}
	}

详细介绍每个初始化器中了什么
3.1 DelegatingApplicationContextInitializer

源码

	public void initialize(ConfigurableApplicationContext context) {
		ConfigurableEnvironment environment = context.getEnvironment();
		List<Class<?>> initializerClasses = getInitializerClasses(environment);

        // 这里由于initializerClasses是空的,所以并没有执行后面的逻辑。
		if (!initializerClasses.isEmpty()) {
			applyInitializerClasses(context, initializerClasses);
		}
	}

这里由于initializerClasses是空的,所以并没有执行后面的逻辑。

3.2 ContextIdApplicationContextInitializer

源码

	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
	}

这里是给ApplicationContext设置ID,我debug到这里,设置的id为application

3.3 ConfigurationWarningsApplicationContextInitializer

源码:

	public void initialize(ConfigurableApplicationContext context) {
		context.addBeanFactoryPostProcessor(
				new ConfigurationWarningsPostProcessor(getChecks()));
	}

 往ApplicationContext容器中注册了beanFactoryPostProcessors后置处理器ConfigurationWarningsPostProcessor

3.4 ServerPortInfoApplicationContextInitializer

源码:

	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.addApplicationListener(
				new ApplicationListener<EmbeddedServletContainerInitializedEvent>() {

					@Override
					public void onApplicationEvent(
							EmbeddedServletContainerInitializedEvent event) {
						ServerPortInfoApplicationContextInitializer.this
								.onApplicationEvent(event);
					}

				});
	}

ApplicationContext容器中注册了事件监听器(我们暂时就叫它ServerPortInfoApplicationContextInitializer$listener),监听EmbeddedServletContainerInitializedEvent事件。

3.5 SharedMetadataReaderFactoryContextInitializer

源码

	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.addBeanFactoryPostProcessor(
				new CachingMetadataReaderFactoryPostProcessor());
	}

ApplicationContext容器中注册了beanFactoryPostProcessors后置处理器CachingMetadataReaderFactoryPostProcessor

3.6 AutoConfigurationReportLoggingInitializer

源码

	public void initialize(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		applicationContext.addApplicationListener(new AutoConfigurationReportListener());
		if (applicationContext instanceof GenericApplicationContext) {
			// Get the report early in case the context fails to load
			this.report = ConditionEvaluationReport
					.get(this.applicationContext.getBeanFactory());
		}
	}

ApplicationContext容器中注册了事件监听器AutoConfigurationReportListener

4.listeners.contextPrepared(context)方法

源码:

调用SpringApplicationRunListeners类的contextPrepared方法

	public void contextPrepared(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextPrepared(context);
		}
	}

这里的this.listeners只有一个,是EventPublishingRunListener类。

实际上调用了EventPublishingRunListener类的contextPrepared方法,而这个方法里面还是空的,等于什么都没做。

5.打印日志

源码

		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

springboot启动时控制台的这两句日志就是这里打印的。 

2019-02-21 11:07:54.421  INFO 60456 --- [           main] com.sid.App                              : Starting App on SKY-20180917SEE with PID 60456 (D:\gitrep\test-aop\target\classes started by Administrator in D:\gitrep\test-aop)
2019-02-21 11:07:57.419  INFO 60456 --- [           main] com.sid.App                              : No active profile set, falling back to default profiles: default

6.把SpringApplicationArguments、SpringBootBanner以单例形式注册到BeanFactory中

源码

		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

7.load(context, sources.toArray(new Object[sources.size()]))方法

源码

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

 这里的sources就是我们编写的带@SpringBootApplication注解的启动类

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

load方法源码

protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug(
					"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		BeanDefinitionLoader loader = createBeanDefinitionLoader(
				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();
	}

做了2件事:

7.1 createBeanDefinitionLoader方法

创建BeanDefinitionLoader

7.2 loader.load方法

此时只是把资源类(这里只有@SpringBootApplication注解修饰的启动类)注册到BeanFactory中。

流程图:

做了4件事:

1.BeanDefinitionLoader把资源加载进来

2.由BeanDefinitionLoader内部的AnnotatedBeanDefinitionReader解析资源

3.AnnotatedBeanDefinitionReader生成beanDefinition

4.AnnotatedBeanDefinitionReader将BeanDefinition注册到BeanFactory的注册表中。注册表是Map类型,key是beanName,value是BeanDefinition 

 8.listeners.contextLoaded(context)方法

调用SpringApplicationRunListeners类的contextLoaded方法

	public void contextLoaded(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.contextLoaded(context);
		}
	}

该方法中的this.listeners其实只有一个 EventPublishingRunListener类

实际上是调用的EventPublishingRunListener类的contextLoaded方法

源码:

	public void contextLoaded(ConfigurableApplicationContext context) {

        // 获取SpringApplication实例化的时候创建的10个监听器
		for (ApplicationListener<?> listener : this.application.getListeners()) {

            // 如果该监听器是ApplicationContextAware的实例,则把ApplicationContext设置到监听器中
			if (listener instanceof ApplicationContextAware) {
				((ApplicationContextAware) listener).setApplicationContext(context);
			}

           // 把SpringApplication实例化的时候创建的10个监听器Listener注册到ApplicationContext容器中。
			context.addApplicationListener(listener);
		}

        // 广播出ApplicationPreparedEvent事件给相应的监听器执行
		this.initialMulticaster.multicastEvent(
				new ApplicationPreparedEvent(this.application, this.args, context));
	}

该方法做了4件事

8.1 获取SpringApplication实例化的时候创建的10个监听器。

org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
org.springframework.boot.logging.ClasspathLoggingApplicationListener
org.springframework.boot.logging.LoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer

8.2 如果该监听器是ApplicationContextAware的实例,则把ApplicationContext设置到监听器中。

8.3 把SpringApplication实例化的时候创建的10个监听器Listener注册到ApplicationContext容器中。

8.4 广播出ApplicationPreparedEvent事件给相应的监听器。

这里有如下几个监听器,接受到了该事件,并且做出相应的逻辑

8.4.1 ConfigFileApplicationListener

接收到该事件做的逻辑源码

	private void onApplicationPreparedEvent(ApplicationEvent event) {
		this.logger.replayTo(ConfigFileApplicationListener.class);
		addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());
	}

ApplicationContext添加BeanFactoryPostProcessor后置处理器PropertySourceOrderingPostProcessor

8.4.2 LoggingApplicationListener

接收到该事件做的逻辑源码

	private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
		ConfigurableListableBeanFactory beanFactory = event.getApplicationContext()
				.getBeanFactory();
		if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
			beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
		}
	}

给beanFactory注册了单例 springBootLoggingSystem

8.4.3 BackgroundPreinitializer

接收到该事件做的逻辑源码

由于这个监听器没有监听ApplicationPreparedEvent事件,所以什么逻辑都没做

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

8.4.4 DelegatingApplicationListener

接收到该事件做的逻辑源码

由于这个监听器没有监听ApplicationPreparedEvent事件,所以什么逻辑都没做

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

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值