SpringBoot - 启动流程分析

SpringBoot - 默认启动类 spring.factories

# PropertySource Loaders

org.springframework.boot.env.PropertySourceLoader=\

org.springframework.boot.env.PropertiesPropertySourceLoader,\

org.springframework.boot.env.YamlPropertySourceLoader

# Run Listeners

org.springframework.boot.SpringApplicationRunListener=\

org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters

org.springframework.boot.SpringBootExceptionReporter=\

org.springframework.boot.diagnostics.FailureAnalyzers

# Application Context Initializers

org.springframework.context.ApplicationContextInitializer=\

org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\

org.springframework.boot.context.ContextIdApplicationContextInitializer,\

org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\

org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners

org.springframework.context.ApplicationListener=\

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.context.logging.ClasspathLoggingApplicationListener,\

org.springframework.boot.context.logging.LoggingApplicationListener,\

org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

# Environment Post Processors

org.springframework.boot.env.EnvironmentPostProcessor=\

org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\

org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\

org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor

# Failure Analyzers

org.springframework.boot.diagnostics.FailureAnalyzer=\

org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\

org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

# FailureAnalysisReporters

org.springframework.boot.diagnostics.FailureAnalysisReporter=\

org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

SpringBoot-启动流程分析

http://blog.csdn.net/doegoo/article/details/52471310

https://www.processon.com/special/template/5d9f1a26e4b06b7d6ec5cfd4

1.初始化SpringApplication

new SpringApplication(primarySources).run(args);

@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = deduceWebApplicationType();
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

获取所有 ApplicationContextInitializer & ApplicationListener

1. SpringFactoriesLoader.loadFactoryNames(type, classLoader));

2. createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

// 从指定位置 META-INF/spring.factories 加载 FactoryNames

2.执行run()方法

	/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
        // getSpringFactoriesInstances 从 spring.factories 加载
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, exceptionReporters, ex);
			throw new IllegalStateException(ex);
		}
		listeners.running(context);
		return context;
	}

1.SpringApplicationRunListeners listeners = getRunListeners(args);

listeners.starting(); //触发 ApplicationStartingEvent 事件

// SpringApplicationRunListener接口规定了Boot的生命周期,在各个生命周期广播相应的事件,调用实际的ApplicationListener

2.ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments)

a>getOrCreateEnvironment();

//创建标准环境

b>configureEnvironment(environment, applicationArguments.getSourceArgs());

//绑定 CommandLinePropertySource ,获取命令行参数

//绑定Profile environment.setActiveProfiles(StringUtils.toStringArray(profiles)); 指定ActiveProfile

c>listeners.environmentPrepared(environment); //触发 EnvironmentPrepared 事件

ConfigFileApplicationListener 是 Spring Boot 中处理配置文件的监听器

1.监听 onApplicationEnvironmentPreparedEvent 后获取所有的 EnvironmentPostProcessor 执行 postProcessEnvironment 方法

2.在自身的 postProcessEnvironment 方法中实现 区分 Profile 后加载 Spring 配置文件

3.监听 onApplicationEnvironmentPreparedEvent 后添加 PropertySourceOrderingPostProcessor implements BeanFactoryPostProcessor

3.createApplicationContext();

// 实例化 AnnotationConfigServletWebServerApplicationContext || AnnotationConfigApplicationContext

public class AnnotationConfigServletWebServerApplicationContext

extends ServletWebServerApplicationContext implements AnnotationConfigRegistry

父类默认构造方法实现

public GenericApplicationContext() {

this.beanFactory = new DefaultListableBeanFactory();

}

4.prepareContext(context, environment, listeners, applicationArguments,printedBanner)

a> context.setEnvironment(environment);

b> postProcessApplicationContext(context);

// 注册BeanNameGenerator AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR

c> applyInitializers(context);

// 调用 ApplicationContextInitializer..initialize(context) 初始化方法

d> listeners.contextPrepared(context); // 空方法

e> load(context, sources.toArray(new Object[0]));

// 把source也就是主类当做bean,加载到spring的容器中

[class com.liuwei.springboot.MybatisApplication]

f> listeners.contextLoaded(context); // 触发 ApplicationPreparedEvent 事件

5.1 refreshContext(context);

https://www.jianshu.com/p/a0a5088a651d?utm_campaign=hugo

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				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();
			}
		}
	}

https://www.jianshu.com/p/a0a5088a651d?utm_campaign=hugo

https://www.cnblogs.com/disandafeier/p/12081301.html

// Prepare this context for refreshing.

(1) prepareRefresh();

初始化 context environment 中占位符

对系统的环境变量或者系统属性进行准备和校验

// Tell the subclass to refresh the internal bean factory.

(2) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

this.beanFactory = new DefaultListableBeanFactory(); //创建并初始化beanFactory

// Prepare the bean factory for use in this context.

(3)prepareBeanFactory(beanFactory);

//对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等

//设置SPEL表达式#{key}的解析器

beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

//设置资源编辑注册器,如PerpertyEditorSupper的支持

beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

//添加ApplicationContextAwareProcessor处理器

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

//在依赖注入忽略实现*Aware的接口,beanFactory.ignoreDependencyInterface 如EnvironmentAware、ApplicationEventPublisherAware,ApplicationContextAware ,ResourceLoaderAware,EmbeddedValueResolverAware,MessageSourceAware等

// 忽略的自动装配(也就是实现了这些接口的Bean,不要Autowired自动装配了)

//注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// 注入一些其它信息的bean,比如environment、systemProperties、SystemEnvironment等

// Allows post-processing of the bean factory in context subclasses.

(4) postProcessBeanFactory(beanFactory);

https://fangjian0423.github.io/2017/05/10/springboot-context-refresh/

beanFactory.addBeanPostProcessor(

new WebApplicationContextServletContextAwareProcessor(this));

GenericWebApplicationContext容器会在BeanFactory中添加ServletContextAwareProcessor用于处理ServletContextAware类型的bean初始化的时候调用setServletContext

// Invoke factory processors registered as beans in the context.

(5)invokeBeanFactoryPostProcessors(beanFactory);

找出beanFactory中所有的实现了BeanDefinitionRegistryPostProcessor接口和BeanFactoryPostProcessor接口的bean

将程序中的所有bean放入到beanDefinitionMap中,注意这一步并没有实例化bean,而是获得bean的beanDefinition

// Register bean processors that intercept bean creation.

(6)registerBeanPostProcessors(beanFactory);

找到BeanPostProcessor的实现,排序后注册到容器内

// Initialize message source for this context.

(7)initMessageSource();

初始化国际化相关属性

// Initialize event multicaster for this context.

(8)initApplicationEventMulticaster();

初始化事件广播器

// Initialize other special beans in specific context subclasses.

(9)onRefresh();

createWebServer(); // 创建Web容器

// Check for listener beans and register them.

(10)registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.

(11)finishBeanFactoryInitialization(beanFactory);

将beanDefinitionMap中的非懒加载的bean都实例化

// spring bean 的实例化过程 https://www.cnblogs.com/kevin-yuan/p/12157017.html

// Last step: publish corresponding event.

(12)finishRefresh();

// Reset common introspection caches in Spring's core, since we

// might not ever need metadata for singleton beans anymore...

(13)resetCommonCaches();

5.2 registerShutdownHook()

6.afterRefresh(context, applicationArguments); // 空方法

7.listeners.started(context); // 触发 ApplicationStartedEvent 事件

8.callRunners(context, applicationArguments);

// 执行 ApplicationRunner & CommandLineRunner

9.listeners.running(context); // 触发 ApplicationReadyEvent 事件

 Application 启动事件机制

ApplicationContextInitializer

如果我们真的需要自定义一个ApplicationContextInitializer,通过SpringFactoriesLoader机制进行配置,或者通过SpringApplication.addInitializers(..)设置即可

ApplicationListener(支持的事件类型四种)

ApplicationStartedEvent::spring boot启动开始时执行的事件

ApplicationEnvironmentPreparedEvent :spring boot 对应Enviroment已经准备完毕,但此时上下文context还没有创建。

ApplicationPreparedEvent :spring boot上下文context创建完成,但此时spring中的bean是没有完全加载完成的

ApplicationFailedEvent:spring boot启动异常时执行事件 

如果我们要为SpringBoot应用添加自定义的ApplicationListener,有两种方式:

1)通过SpringApplication.addListeners(..)或者SpringApplication.setListeners(..)方法添加一个或者多个自定义的ApplicationListener;

2)借助SpringFactoriesLoader机制,在META-INF/spring.factories文件添加配置

EnvironmentPostProcessor

BeanPostProcessor

BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor

Aware

@Configuration 和 Auto-configuration

都是使用@Configuration注解的类,这些类里都可以定义@Bean@Import@ImportResource

都可以使用@Condition*来根据情况选择是否加载

AnnotatedBeanDefinitionReader

ConfigurationClassPostProcessor

ConfigurationClassParser

EnableAutoConfigurationImportSelector

内置类说明

LoggingApplicationListener

LoggingApplicationListener用来配置日志系统的,比如logback、log4j。

StandardEnvironment

StandardEnvironment有一个MutablePropertySources,它里面有多个PropertySourcePropertySource负责提供property(即property的提供源),目前已知的PropertySource实现有:MapPropertySourceSystemEnvironmentPropertySourceCommandLinePropertySource等。

在实际项目中资源信息如果能够动态获取在修改线上产品配置时及其方便,下面来展示一个加载动态获取资源的案例,而不是加载写死的properties文件信息

首先构造PropertySource,然后将其添加到Enviroment中

ConfigFileApplicationListener

ConfigFileApplicationListener用来将application.properties加载到StandardEnvironment中。

ConfigFileApplicationListener内部使用了EnvironmentPostProcessor

ApplicationContextAwareProcessor

  1. EnvironmentAware
  2. EmbeddedValueResolverAware
  3. ResourceLoaderAware
  1. ApplicationEventPublisherAware
  2. MessageSourceAware
  3. ApplicationContextAware

AnnotationConfigApplicationContext

AnnotatedBeanDefinitionReader

一、@Enable*注释

@Enable*注释并不是新发明的注释,早在Spring 3框架就引入了这些注释,用这些注释替代XML配置文件。

很多Spring开发者都知道@EnableTransactionManagement注释,它能够声明事务管理;@EnableWebMvc注释,它能启用Spring MVC;以及@EnableScheduling注释,它可以初始化一个调度器。

这些注释事实上都是简单的配置,通过@Import注释导入。

二 、

spring boot 默认支持两个格式的配置文件:.properties .yml。

Spring Boot 还提供了基于类型安全的配置方式,通过@ConfigurationProperties将properties属性和一个Bean及其属性关联,从而实现类型安全的配置

@ConfigurationProperties(prefix = "user")

三 Profile配置

Profile是Spring用来针对不同环境对不同配置提供支持的,全局Profile配置使用

application-{profile}.properties 如:application-prod.properties

猜你喜欢

转载自blog.csdn.net/lewee0215/article/details/111828975
今日推荐