diff --git "a/springboot-source-code-analysis/(4)347円263円273円347円273円237円345円210円235円345円247円213円345円214円226円345円231円250円350円247円243円346円236円220円.md" "b/springboot-source-code-analysis/(4)347円263円273円347円273円237円345円210円235円345円247円213円345円214円226円345円231円250円350円247円243円346円236円220円.md"
new file mode 100644
index 0000000..8e82986
--- /dev/null
+++ "b/springboot-source-code-analysis/(4)347円263円273円347円273円237円345円210円235円345円247円213円345円214円226円345円231円250円350円247円243円346円236円220円.md"
@@ -0,0 +1,210 @@
+### 系统初始化器解析
+
+#### 1、ApplicationContextInitializer作用
+
+```java
+/**
+ * Callback interface for initializing a Spring {@link ConfigurableApplicationContext}
+ * prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}.
+ *
+ *
Typically used within web applications that require some programmatic initialization
+ * of the application context. For example, registering property sources or activating
+ * profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment()
+ * context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support
+ * for declaring a "contextInitializerClasses" context-param and init-param, respectively.
+ *
+ *
{@code ApplicationContextInitializer} processors are encouraged to detect
+ * whether Spring's {@link org.springframework.core.Ordered Ordered} interface has been
+ * implemented or if the @{@link org.springframework.core.annotation.Order Order}
+ * annotation is present and to sort instances accordingly if so prior to invocation.
+ *
+ * @author Chris Beams
+ * @since 3.1
+ * @param the application context type
+ * @see org.springframework.web.context.ContextLoader#customizeContext
+ * @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM
+ * @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses
+ * @see org.springframework.web.servlet.FrameworkServlet#applyInitializers
+ */
+public interface ApplicationContextInitializer {
+
+ /**
+ * Initialize the given application context.
+ * @param applicationContext the application to configure
+ */
+ void initialize(C applicationContext);
+}
+
+```
+
+- 上下文刷新即refersh方法前调用;
+- 用来编码设置一些属性变量,通常用在web环境中;
+- 可以通过order接口进行排序;
+
+
+
+#### 2、ApplicationContextInitializer调用点,通过SpringFactoriesLoder中的this.initializers进行初始化
+
+image-20210802174243992
+
+- 步骤一:在刷新上下文前,调用prepareContext#()准备上下文的方法
+
+```java
+public ConfigurableApplicationContext run(String... args) {
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+ ConfigurableApplicationContext context = null;
+ Collection exceptionReporters = new ArrayList();
+ configureHeadlessProperty();
+ SpringApplicationRunListeners listeners = getRunListeners(args);
+ 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, ex, exceptionReporters, listeners);
+ throw new IllegalStateException(ex);
+ }
+
+ try {
+ listeners.running(context);
+ }
+ catch (Throwable ex) {
+ handleRunFailure(context, ex, exceptionReporters, null);
+ throw new IllegalStateException(ex);
+ }
+ return context;
+ }
+```
+
+- 步骤二:调用初始化器 applyInitializers(context) 方法
+
+```java
+ private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
+ SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
+ context.setEnvironment(environment);
+ postProcessApplicationContext(context);
+ // 调用初始化器方法
+ applyInitializers(context);
+ listeners.contextPrepared(context);
+ if (this.logStartupInfo) {
+ logStartupInfo(context.getParent() == null);
+ logStartupProfileInfo(context);
+ }
+ // Add boot specific singleton beans
+ ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
+ beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
+ if (printedBanner != null) {
+ beanFactory.registerSingleton("springBootBanner", printedBanner);
+ }
+ if (beanFactory instanceof DefaultListableBeanFactory) {
+ ((DefaultListableBeanFactory) beanFactory)
+ .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
+ }
+ // Load the sources
+ Set sources = getAllSources();
+ Assert.notEmpty(sources, "Sources must not be empty");
+ load(context, sources.toArray(new Object[0]));
+ listeners.contextLoaded(context);
+ }
+```
+
+- 步骤三:系统初始化器的具体实现,调用 ApplicationContextInitializer.initialize() 方法
+
+```java
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected void applyInitializers(ConfigurableApplicationContext context) {
+ // getInitializers() 方法,从this.initializers 成员中,获取初始化器的实现
+ for (ApplicationContextInitializer initializer : getInitializers()) {
+ // 判断初始化器的实现类,是否实现了ApplicationContextInitializer接口类
+ Class> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
+ ApplicationContextInitializer.class);
+ Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
+ // 调用初始化器实现类中的 initialize#() 方法,进行初始化
+ initializer.initialize(context);
+ }
+ }
+```
+
+
+
+#### 3、添加系统初始化器 this.initializers 成员的两种方式
+
+- 第一种:定义在spring.factories文件中,通过SpringFactoriesLoader发现与注册
+
+ ```java
+ SpringBoot框架中从类路径jar包中读取特定的文件(META-INF/spring.factories)实现扩展类的载入
+ 最终调用SpringApplication.addInitializers#()方法添加到this.initializers成员中
+ ```
+
+
+
+- 第二种:通过SpringApplication.addInitializers#() 方法手动添加到系统初始化器中
+
+ ```java
+ public static void main(String[] args) {
+ // SpringApplication.run(SpringbootSourceCodeAnalysisApplication.class, args);
+ SpringApplication springApplication = new SpringApplication(SpringbootSourceCodeAnalysisApplication.class);
+ // 手动添加一个框架的初始化器
+ springApplication.addInitializers(new SecondInitializer());
+ springApplication.run();
+ }
+ ```
+
+
+
+- 第三种:在application.properties 配置文件中定义环境变量,通过DelegatingApplicationContextInitializer 发现与注册
+
+ - 步骤一:DelegatingApplicationContextInitializer 在Spring框架中,会被SpringFactoriesLoader 自动加载,且优先级最高 order = 0
+
+ ```java
+ # 在spring.factories配置文件中
+ # Application Context Initializers
+ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
+ ```
+
+ - 步骤二:通过DelegatingApplicationContextInitializer 中的 initialize#() 方法,获取ApplicationContextInitializer.class的实现
+
+ ```java
+ private static final String PROPERTY_NAME = "context.initializer.classes";
+
+ private int order = 0;
+
+ @Override
+ public void initialize(ConfigurableApplicationContext context) {
+ // 获取application.properties配置中的 context.initializer.classes 属性
+ ConfigurableEnvironment environment = context.getEnvironment();
+ // 获取所有 ApplicationContextInitializer.class 接口的实现类
+ List> initializerClasses = getInitializerClasses(environment);
+ if (!initializerClasses.isEmpty()) {
+ // 初始化系统初始化器
+ applyInitializerClasses(context, initializerClasses);
+ }
+ }
+ ```
+
+
+
+#### 4、ApplicationContextInitializer.class 的调用流程总结
+
+image-20210802183526156
+
+
+