SpringBoot source code analysis (7)--prepareContext/prepare application context

I. Introduction

This article is based on the spring-boot-2.2.14.BUILD-SNAPSHOT source code analysis of prepareContext to prepare the application context.

2. prepareContext

Following the above, this article continues to analyze the run method of SpringApplication and looks at the prepareContext line of code
Insert image description here
request parameters:

Parameter Type Brief description of parameters
ConfigurableApplicationContext context The return value of the createApplicationContext() method represents the application context
ConfigurableEnvironment environment Interface class for system environment variable information
SpringApplicationRunListeners listeners Collection class of SpringApplicationRunListener
ApplicationArguments applicationArguments Application parameters
Banner printedBanner Printed Banner information

Enter method implementation:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    
    
	// 1、设置环境对象
	//统一ApplicationContext和Application,使用Application的environment
	context.setEnvironment(environment);
	// 2、注册组件 设置ApplicationContext的beanNameGenerator、resourceLoader、
	postProcessApplicationContext(context);
	// 3、应用初始化器对ApplicationContext进行初始化处理(Initializers在构造SpringApplication时就从spring.factories中加载到了)
	applyInitializers(context);
	// 4、发布ApplicationContext准备妥当事件
	listeners.contextPrepared(context);
	// 5、打印startup日志信息
	if (this.logStartupInfo) {
    
    
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// 6 、添加特定的单例beans到 beanFactory中
	// 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);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// Load the sources加载资源
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	// 加载启动类,见启动类注入容器中
	load(context, sources.toArray(new Object[0]));
	// 触发contextLoaded事件
	listeners.contextLoaded(context);
}

To prepare the application context AnnotationConfigServletWebServerApplicationContext, the following 8 steps were performed

  1. Unify ApplicationContext and environment used by Application
  2. Postprocessing ApplicationContext
  3. Execute Initializers
  4. Post contextPrepared event
  5. Print startup and profile logs
  6. Register a singleton bean
  7. Load startup class
  8. Post contextLoaded event

2.1、context.setEnvironment

Unify ApplicationContext and environment used by Application

public class AnnotationConfigServletWebServerApplicationContext
        extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
    
    
        
    @Override
    public void setEnvironment(ConfigurableEnvironment environment) {
    
    
        //显式调用父类AbstractApplicationContext的setEnvironment方法
        super.setEnvironment(environment);
        //调用AnnotatedBeanDefinitionReader#setEnvironment()方法
        this.reader.setEnvironment(environment);        
        //ClassPathBeanDefinitionScanner继承了ClassPathScanningCandidateComponentProvider,所以调用了父类setEnvironment方法
        this.scanner.setEnvironment(environment);
    }
    
}

Replace all relevant environments in the context with the environment created in SpringApplication. Do you still remember the questions in " SpringBoot Source Code Analysis (5)-createApplicationContext to create an application context "? The extension is: there were two environments in our application before, one in the context and one in SpringApplication. After this method, only the environment in SpringApplication will exist, and the original environment in context will be recycled.

Regarding this point, we mentioned a flaw in the previous article, because although the native environment of the container is replaced here, when the SpringBootExceptionReporter was initialized before, the native environment was set to the exception analyzer, and the environment held by these analyzers did not Getting synchronized updates is not the environment object we actually use.

2.2、postProcessApplicationContext(context);

The following three steps were performed

  1. Set beanNameGenerator of ApplicationContext
  2. Set the resourceLoader and classLoader of ApplicationContext
  3. Set the type conversion service of ApplicationContext
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    
    
    //beanNameGenerator默认为null,所以此处没有设置
    if (this.beanNameGenerator != null) {
    
    
        //如果beanNameGenerator不为空
        //那么注册一个名为internalConfigurationBeanNameGenerator
        //值为beanNameGenerator的单例bean
        context.getBeanFactory().registerSingleton(
                AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                this.beanNameGenerator);
    }
    //resourceLoader默认为null,所以此处没有设置
    if (this.resourceLoader != null) {
    
    
        //如果resourceLoader不为空
        if (context instanceof GenericApplicationContext) {
    
    
            //context是GenericApplicationContext子类
            //那么设置上下文context的resourceLoader
            ((GenericApplicationContext) context)
                    .setResourceLoader(this.resourceLoader);
        }
        if (context instanceof DefaultResourceLoader) {
    
    
            //如果当前上下文是DefaultResourceLoader的子类
            //那么设置上下文context的classLoader
            ((DefaultResourceLoader) context)
                    .setClassLoader(this.resourceLoader.getClassLoader());
        }
    }
    //this.addConversionService默认为true
    if (this.addConversionService) {
    
    
        //设置类型转换Service
        context.getBeanFactory().setConversionService(
                ApplicationConversionService.getSharedInstance());
    }
}

First, check whether there is a custom BeanNameGenerator in the SpringApplication object. If so, register it in the singleton pool of the container. This object is used to generate names for the beans in the container. When the Spring container new comes out, it will generate one by default. The naming strategy is to lowercase the class name, but the object in SpringApplication is null by default.

Then check whether the SpringApplication object has a custom ResourceLoader. If so, assign it to the container. We have analyzed this before, and the default is null.

The last if branch, addConversionService is set to true by default in the constructor of the SpringApplication object, so if will be used, it sets a ConversonService for the container. This class is used for type conversion, such as String to Integer, etc., in fact I have seen it several times in previous articles.
Insert image description here

2.3、applyInitializers(context)

What is loaded is the ApplicationContextInitializer list in META-INF/spring.factories, and its initialize method is called in sequence.

protected void applyInitializers(ConfigurableApplicationContext context) {
    
    
	for (ApplicationContextInitializer initializer : getInitializers()) {
    
    
	    //断言判断initializer的类型是否符合条件
		Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
				ApplicationContextInitializer.class);
		Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
		//执行各个initializer的初始化initialize方法
		initializer.initialize(context);
	}
}

The initializers are obtained during the initialization of SpringApplication. To obtain the source code, please refer to " SpringBoot Source Code Analysis (2)-SpringBoot Startup Source Code (Ten Thousand Words Graphic Source Code Debug Explains the Springboot Startup Principle)" . A total of 7 initializers are obtained:

  • DelegatingApplicationContextInitializer
  • SharedMetadataReaderFactoryContextInitializer
  • ContextIdApplicationContextInitializer
  • ConfigurationWarningsApplicationContextInitializer
  • ServerPortInfoApplicationContextInitializer
  • ConditionEvaluationReportLoggingListener
  • RSocketPortInfoApplicationContextInitializer

This article first sorts out the context of the prepareContext method. As for the initialization done by these built-in ApplicationContextInitializers, we will analyze it separately in our next article " SpringBoot Source Code Analysis (8)-Built-in ApplicationContextInitializer "

All these initialization classes do not perform the substantive operation of starting the service. They all register objects and bury the point. The initialization method is actually called later by invokeBeanFactoryPostProcessors, and before the project is started.

2.4. Publish the ApplicationContextInitializedEvent event

// 4、发布ApplicationContext准备妥当事件
listeners.contextPrepared(context);

Application container initialization completion event, the listeners interested in this event are

  • BackgroundPreinitializer
  • DelegatingApplicationListener

BackgroundPreinitializer
extension point, background process initializer, used for multi-threaded execution of background time-consuming tasks, the ApplicationContextInitializedEvent event is not processed here

DelegatingApplicationListener
extension point, proxy listener, continues to distribute events, does not handle the ApplicationContextInitializedEvent event

2.5. Print startup and profile logs

//logStartupInfo默认为true
if (this.logStartupInfo) {
    
    
    //判断是否有父容器,打印项目启动信息
    // Starting Demo3Application on pcname with PID 12372 (E:\workspace\demo3\target\classes started by username in E:\workspace\demo3)
    logStartupInfo(context.getParent() == null);

    //打印profile
    //No active profile set, falling back to default profiles: default
    logStartupProfileInfo(context);
}

This code determines whether the current container has a parent container. If not, it is considered to be the root container for project startup, and a line of log will be printed, including startup class, current server name, project path, PID, etc.

2023-07-18 10:35:07.105  INFO 3136 --- [           main] com.example.demo.Demo3Application        : Starting Demo3Application on hualsd with PID 3136 (D:\WorkSpace\demo3\target\classes started by 188 in D:\WorkSpace\demo3)
2023-07-18 10:35:32.693  INFO 3136 --- [           main] com.example.demo.Demo3Application        : The following profiles are active: sit

2.6. Register Singleton Bean

Registered two singleton beans

  • Command line parameter bean, name is springApplicationArguments, value is applicationArgument
  • banner bean, the name is springBootBanner, the value is printedBanner
//注册命令行参数bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
    
    
    //banner bean
    beanFactory.registerSingleton("springBootBanner", printedBanner);
}

Finally, the registerSingleton method will register them into the singletonObjects container. As we can see from the name, this is a container for storing singleton objects.
Insert image description here

2.6.1. Manual registration of singleton Bean process

Call the DefaultListableBeanFactory#registerSingleton method, and explicitly call the parent class DefaultSingletonBeanRegistry#registerSingleton method

DefaultListableBeanFactory Manually registering a singleton bean
Manually registering a singleton bean is different from scanning the bean definition and then registering the singleton bean. The manually registered singleton bean is not maintained in the beanDefinitionMap, but the beanName is maintained in manualSingletonNames.

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    

    //注册单例bean
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
    
    
        super.registerSingleton(beanName, singletonObject);

        //判断bean的创建过程是否已经开始了
        //调用抽象父类AbstractBeanFactory#hasBeanCreationStarted()方法
        //判断AbstractBeanFactory成员变量alreadyCreated Set不为空
        if (hasBeanCreationStarted()) {
    
    
            //bean创建过程已经开始了
            //锁住成员变量beanDefinitionMap
            synchronized (this.beanDefinitionMap) {
    
    
                if (!this.beanDefinitionMap.containsKey(beanName)) {
    
    
                    //如果bean定义Map,  beanDefinitionMap已经包含了bean
                    //维护到手工单例bean名称manualSingletonNames中
                    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames.size() + 1);
                    updatedSingletons.addAll(this.manualSingletonNames);
                    updatedSingletons.add(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
    
    
            // bean还没有注册过, 仍处于启动注册阶段
            if (!this.beanDefinitionMap.containsKey(beanName)) {
    
    
                //如果beanDefinitionMap不包含beanName
                //那么添加到manualSingletonNames
                this.manualSingletonNames.add(beanName);
            }
        }

        //清空allBeanNamesByType和singletonBeanNamesByType
        clearByTypeCache();
    }
}

DefaultSingletonBeanRegistry manually registers the singleton Bean
, adds beanName to registeredSingletons, saves beanName and the corresponding object in singletonObjects, and deletes the beanFactory and earlySingleton corresponding to beanName.

//默认单例bean注册器
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    
    
    
    //缓存单例bean, key为bean名称,value为bean实例
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    //缓存beanFactory, key为bean名称, value为beanFactory
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    //早期单例缓存, key为bean名称, value为bean实例
    //为了解决循环依赖而引入的
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    //单例bean名称set
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    //正在创建的单例bean名称set
    private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));


    //手工注册单例bean
    @Override
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
    
    
        //判断名称和值不可以为空
        Assert.notNull(beanName, "Bean name must not be null");
        Assert.notNull(singletonObject, "Singleton object must not be null");
        synchronized (this.singletonObjects) {
    
    
            //判断bean是否为空
            Object oldObject = this.singletonObjects.get(beanName);
            if (oldObject != null) {
    
    
                //不为空抛异常
                throw new IllegalStateException("Could not register object [" + singletonObject +
                        "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
            }
            //添加一个单例bean
            addSingleton(beanName, singletonObject);
        }
    }
    
    //添加一个单例bean
    protected void addSingleton(String beanName, Object singletonObject) {
    
    
        synchronized (this.singletonObjects) {
    
    
            //保存到singletonObjects的map中
            this.singletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            //添加beanName
            this.registeredSingletons.add(beanName);
        }
    }
}

Then register the singleton bean and continue the analysis.

Set whether to allow overriding with the same name (setAllowBeanDefinitionOverriding), which is false by default (default value of the allowBeanDefinitionOverriding property). If true, the subsequent BeanDefinition data will overwrite the previous one.
Insert image description here

Add beanFactory lazy loading post-processor (addBeanFactoryPostProcessor). Since lazy loading is not enabled by default, the lazy loading post-processor will not be added by default.
Insert image description here

2.7. Initialize BeanDefinitionLoader and load Application

Next let’s look at a more important load method

Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));

getAllSources obtains the primarySources attribute of the SpringApplication object, and this attribute is assigned a value in the SpringApplication constructor, which is our startup class Demo3Application.class
Insert image description here

Next enter the load method

protected void load(ApplicationContext context, Object[] sources) {
    
    
    if (logger.isDebugEnabled()) {
    
    
        logger.debug(
                "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    //实例化BeanDefinitionLoader
    BeanDefinitionLoader loader = createBeanDefinitionLoader(
            getBeanDefinitionRegistry(context), sources);
    //this.beanNameGenerator为null
    if (this.beanNameGenerator != null) {
    
    
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    //this.resourceLoader为null
    if (this.resourceLoader != null) {
    
    
        loader.setResourceLoader(this.resourceLoader);
    }
    //this.environment为null
    if (this.environment != null) {
    
    
        loader.setEnvironment(this.environment);
    }
    //调用load()方法,加载各个sources
    loader.load();
}

First, a BeanDefinitionLoader is generated to load the member variable sources of SpringApplication. There is only one object of Demo3Application.class in the current sources list.

First create a BeanDefinitionLoader through the createBeanDefinitionLoader method, which can load a class into a BeanDefinition. The first parameter is the spring container, and the second parameter is our startup class.

BeanDefinitionLoader constructor

  /**
 * 构造函数
   */
  BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    
    
      Assert.notNull(registry, "Registry must not be null");
      Assert.notEmpty(sources, "Sources must not be empty");
      //传入的sources, 目前只有Demo3Application.class
      this.sources = sources;
      this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
      this.xmlReader = new XmlBeanDefinitionReader(registry);
      if (isGroovyPresent()) {
    
    
          //使用了groovy
          this.groovyReader = new GroovyBeanDefinitionReader(registry);
      }
      this.scanner = new ClassPathBeanDefinitionScanner(registry);
      //排除sources扫描
      this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
  }

In the construction method of BeanDefinitionLoader, an AnnotatedBeanDefinitionReader object will be created. This class has been created once in the constructor of the spring container. The spring container is not used directly here, but a new one is created. The construction of the Reader will be repeated. process, but the method of registering beans to the spring container is checked for nullity before execution, so there will be no repeated registration, similar to the following code

if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
    
    
    def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
}

Back to the load method, the next few if branches will not enter. By default, the beanNameGenerator, resourceLoader, and environment in SpringApplication are all null. Note that the environment we actually use is created in the run method of the SpringApplication object and does not Assigned to its own environment variable, so it is still null here

Enter the last line of the load method

 /**
  * 加载sources
  */
 public int load() {
    
    
     int count = 0;
     for (Object source : this.sources) {
    
    
         count += load(source);
     }
     return count;
 }

Under normal circumstances, there is only one startup class, continue to follow the load method

//加载Object资源
private int load(Object source) {
    
    
    Assert.notNull(source, "Source must not be null");
    if (source instanceof Class<?>) {
    
    
        //加载类资源
        return load((Class<?>) source);
    }
    if (source instanceof Resource) {
        //加载Resource资源
        return load((Resource) source);
    }
    if (source instanceof Package) {
        //加载Package资源
        return load((Package) source);
    }
    if (source instanceof CharSequence) {
        //加载字符串资源
        return load((CharSequence) source);
    }
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

Our startup class is of class type, take the first branch

//加载类资源
private int load(Class<?> source) {
    
    
    if (isGroovyPresent()
            && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
    
    
        // 使用了groovy,加载groovy资源
        GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                GroovyBeanDefinitionSource.class);
        load(loader);
    }
    //如果有@Component注解
    if (isComponent(source)) {
    
    
        this.annotatedReader.register(source);
        return 1;
    }
    return 0;
}

The isComponent method determines whether there is an @Component annotation on the startup class. The startup class is annotated with @SpringBootApplication. It is a composite annotation and contains the @Component annotation internally. Therefore, this branch is established and enters the register method.

public class AnnotatedBeanDefinitionReader {
    
    

    //Class列表注册Bean定义
    public void register(Class<?>... annotatedClasses) {
    
    
        for (Class<?> annotatedClass : annotatedClasses) {
    
    
            //单个Bean注册
            registerBean(annotatedClass);
        }
    }
}

registerBean calls doRegisterBean

public class AnnotatedBeanDefinitionReader {
    
    

     //单个Class注册bean
    public void registerBean(Class<?> annotatedClass) {
    
    
        doRegisterBean(annotatedClass, null, null, null);
    }
    
}

Finally, our startup class will be converted into a BeanDefinition and registered in the BeanDefinitionMap of the spring container. Later, we will use this as a starting point to scan the Controller, Service, etc. in the project and register them in the container.

 //注册Bean定义
  <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
          @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    
    
      //生成注解BeanDefinition
      AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
      
      //判断是否符合@Conditional注解的条件
      //不满足的话, 就不注册Bean
      if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    
    
          return;
      }
      //设置instanceSupplier, //AbstractAutowireCapableBeanFactory#createBeanInstance中调用了instanceSupplier.get()生成bean实例
      abd.setInstanceSupplier(instanceSupplier);
      //Scope元空间
      ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
      abd.setScope(scopeMetadata.getScopeName());
      //生成Bean名称
      String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

      //处理Lazy, Primary, DependsOn, Role, Description注解
      AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
      if (qualifiers != null) {
    
    
          for (Class<? extends Annotation> qualifier : qualifiers) {
    
    
              if (Primary.class == qualifier) {
    
    
                  abd.setPrimary(true);
              }
              else if (Lazy.class == qualifier) {
    
    
                  abd.setLazyInit(true);
              }
              else {
    
    
                  abd.addQualifier(new AutowireCandidateQualifier(qualifier));
              }
          }
      }
      for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
    
    
          //beanDefinition定制器
          customizer.customize(abd);
      }

      //bean定义容器
      BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
      
      //Scope代理模式处理
      //ScopedProxyMode.DEFAULT和NO不需要代理处理
      //INTERFACES使用JDK动态代理
      //TARGET_CLASS使用CGLIB动态代理
      definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
      
      //注册Bean定义
      BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }

After the execution is completed, you can see that our startup class has been added to the BeanDefinitionMap of the Spring container, and the previous classes were all registered in the container during the initialization process of the internal AnnotatedBeanDefinitionReader when the new container was created.
Insert image description here

2.8. Release contextLoaded event

Call listeners.contextLoaded(context), publishing an ApplicationPreparedEvent event.

Like the previous event publishing mechanism, the contextLoaded method of EventPublishingRunListener is finally called.

public void contextLoaded(ConfigurableApplicationContext context) {
    
    
	for (ApplicationListener<?> listener : this.application.getListeners()) {
    
    
		if (listener instanceof ApplicationContextAware) {
    
    
			((ApplicationContextAware) listener).setApplicationContext(context);
		}
		context.addApplicationListener(listener);
	}
	this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}

This for loop traverses all the listeners of the SpringApplication object, which is the ApplicationListener loaded from META-INF/spring.factories when SpringApplication was first created. In the loop, it is judged whether the Listener implements the ApplicationContextAware interface. If so, If so, assign the Spring container to him

This Aware callback is originally executed during the refresh process of the Spring container, but since the listener here may only be stored in a list attribute of the container, it will not be registered in the container, and will not be managed as a Bean. , there is no way to trigger the callback in the normal way during the refresh process of the spring container, so we assign the value manually here.

Then in the last condition of the for loop, add it to the listener list of the spring container. We have mentioned before that after the container is started, the event publishing function will be transferred to the container, and this is an important step. The built-in listener list is given to the container. With the listener list, events can naturally be broadcast to them.

Finally, the event ApplicationPreparedEvent is published. The publishing process is the same as before. There are four listeners of final interest:

  • ConfigFileApplicationListener
  • LoggingApplicationListener
  • BackgroundPreinitializer
  • DelegatingApplicationListener

2.8.1、ConfigFileApplicationListener

Configuration file listener

public class ConfigFileApplicationListener
        implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
    
    
    //事件处理
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
    
    
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
    
    
            onApplicationEnvironmentPreparedEvent(
                    (ApplicationEnvironmentPreparedEvent) event);
        }
        if (event instanceof ApplicationPreparedEvent) {
    
    
            //处理ApplicationPreparedEvent
            onApplicationPreparedEvent(event);
        }
    }
    
    //处理ApplicationPreparedEvent
    private void onApplicationPreparedEvent(ApplicationEvent event) {
    
    
        this.logger.switchTo(ConfigFileApplicationListener.class);
        addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());
    }
    
    //applicationContext中添加一个PropertySourceOrderingPostProcessor
    protected void addPostProcessors(ConfigurableApplicationContext context) {
    
    
        //用于重排序PropertySourceOrderingPostProcessor
        context.addBeanFactoryPostProcessor(
                new PropertySourceOrderingPostProcessor(context));
    }
}

2.8.2、LoggingApplicationListener

Log listener

public class LoggingApplicationListener implements GenericApplicationListener {
    
    

    private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
    
    
        ConfigurableListableBeanFactory beanFactory = event.getApplicationContext()
                .getBeanFactory();
        //注册日志单例bean
        if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
    
    
            beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
        }
    }
    
}

2.8.3、BackgroundPreinitializer

Background pre-initializer, currently does not perform task processing, to facilitate future expansion

2.8.4、DelegatingApplicationListener

Proxy listener, does not do any processing, convenient for future expansion

3. Summary

The main function of this step is to prepare for refreshing the applicationContext below.

  • Unified ApplicationContext and Application environment
  • Set the beanNameGenerator, resouceLoader and classLoader of ApplicationContext, - and set the type conversion Service of beanFactory
  • Execute Initializer
  • Post ApplicationContextInitializedEvent
  • Print startup log and profile log
  • Manually register two singleton beans, command line and banner
  • Initialize BeanDefinitionLoader and load startup class sources
  • Post contextLoaded event

Guess you like

Origin blog.csdn.net/weixin_49114503/article/details/131762297