SpringBoot source code analysis (8)--Built-in ApplicationContextInitializer


This article is based on spring-boot-2.2.14.BUILD-SNAPSHOT source code analysis.

This article is a supplement to the previous prepareContext. During the execution of this method, the ApplicationContextInitializer originally loaded from the META-INF/spring.factories file is traversed, and its initialize method is called in sequence.
Insert image description here

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

When SpringApplication is initialized, a total of 7 built-in ApplicationContextInitializers are loaded. This article will analyze what each built-in initializer does one by one.

spring-boot/src/main/resources/META-INF/spring.factories

# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

1、DelegatingApplicationContextInitializer

Get the ApplicationContextInitializer list configured by the property context.initializer.classesInitializer in the environment and execute its initialize() method.

SpringBoot allows us to customize some ApplicationContextInitializers through various attribute configuration methods. Their calling time is the initialize method of the class.

//代理初始化器
public class DelegatingApplicationContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    
    
        
    private static final String PROPERTY_NAME = "context.initializer.classes";
    
    @Override
    public void initialize(ConfigurableApplicationContext context) {
    
    
        ConfigurableEnvironment environment = context.getEnvironment();
        //获取environment中配置的context.initializer.classes属性
        //其值为各个initializer,用逗号分隔开
        List<Class<?>> initializerClasses = getInitializerClasses(environment);
        if (!initializerClasses.isEmpty()) {
    
    
            //获取到各个initializer,并执行其initialize()方法
            applyInitializerClasses(context, initializerClasses);
        }
    }
            
}

Enter the getInitializerClasses method

private static final String PROPERTY_NAME = "context.initializer.classes";

private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
    
    
	String classNames = env.getProperty(PROPERTY_NAME);
	List<Class<?>> classes = new ArrayList<>();
	if (StringUtils.hasLength(classNames)) {
    
    
		for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
    
    
			classes.add(getInitializerClass(className));
		}
	}
	return classes;
}

It finds the context.initializer.classes property from the environment, parses it into a Class list with commas as delimiters and returns

Since it is only fetched once through the getProperty method, we have analyzed before that this method will traverse all PropertySources from front to back, and return immediately after fetching it, so the context is set in different ways, such as startup parameters, system configuration, etc. initializer.classes, only the one with the highest priority will take effect

Then for the custom initializer found, call the applyInitializerClasses method

private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) {
    
    
	Class<?> contextClass = context.getClass();
	List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
	for (Class<?> initializerClass : initializerClasses) {
    
    
		initializers.add(instantiateInitializer(contextClass, initializerClass));
	}
	applyInitializers(context, initializers);
}

Instantiate first, then call the applyInitializers method

private void applyInitializers(ConfigurableApplicationContext context,
			List<ApplicationContextInitializer<?>> initializers) {
    
    
	initializers.sort(new AnnotationAwareOrderComparator());
	for (ApplicationContextInitializer initializer : initializers) {
    
    
		initializer.initialize(context);
	}
}

Finally their initialize method is called

2、SharedMetadataReaderFactoryContextInitializer

A BeanFactoryPostProcessor of type CachingMetadataReaderFactoryPostProcessor is added. CachingMetadataReaderFactoryPostProcessor will do two things

  • Register a bean with the name internalCachingMetadataReaderFactory and type SharedMetadataReaderFactoryBean, which is used to read the bean's metadata Metadata
  • Get the bean definition with the name internalConfigurationAnnotationProcessor and the type ConfigurationClassPostProcessor, and add to it the internalCachingMetadataReaderFactory with the name metadataReaderFactory and the value internalCachingMetadataReaderFactory.
class SharedMetadataReaderFactoryContextInitializer implements
        ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    
    

    public static final String BEAN_NAME = "org.springframework.boot.autoconfigure."
            + "internalCachingMetadataReaderFactory";

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
    
    
        //spring上下文容器添加一个CachingMetadataReaderFactoryPostProcessor
        applicationContext.addBeanFactoryPostProcessor(
                new CachingMetadataReaderFactoryPostProcessor());
    }
}

The specific type is CachingMetadataReaderFactoryPostProcessor. Like the logic of the first initializer, it is also an internal class and implements the BeanDefinitionRegistryPostProcessor interface. The postProcessBeanFactory method is empty, so you only need to look at its postProcessBeanDefinitionRegistry method.

private static class CachingMetadataReaderFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
    
    
   private CachingMetadataReaderFactoryPostProcessor() {
    
    
    }

	......
	......

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
    }

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
    
        this.register(registry);
        this.configureConfigurationClassPostProcessor(registry);
    }
    ......
}

First, the register method obtains a BeanDefinition from the internal class SharedMetadataReaderFactoryBean and registers it in the BeanDefinitionMap of the container.

private void register(BeanDefinitionRegistry registry) {
    
    
    BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(SharedMetadataReaderFactoryContextInitializer.SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryContextInitializer.SharedMetadataReaderFactoryBean::new).getBeanDefinition();
    registry.registerBeanDefinition("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory", definition);
}

This SharedMetadataReaderFactoryBean, as the name suggests, is a FactoryBean, and it implements the BeanClassLoaderAware interface. In the callback method setBeanClassLoader of this interface, the internal ConcurrentReferenceCachingMetadataReaderFactory is initialized and returned in the getObject method.

static class SharedMetadataReaderFactoryBean implements FactoryBean<ConcurrentReferenceCachingMetadataReaderFactory>, BeanClassLoaderAware, ApplicationListener<ContextRefreshedEvent> {
    
    
    private ConcurrentReferenceCachingMetadataReaderFactory metadataReaderFactory;

    SharedMetadataReaderFactoryBean() {
    
    
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
    
    
        this.metadataReaderFactory = new ConcurrentReferenceCachingMetadataReaderFactory(classLoader);
    }

    public ConcurrentReferenceCachingMetadataReaderFactory getObject() throws Exception {
    
    
        return this.metadataReaderFactory;
    }

The returned ConcurrentReferenceCachingMetadataReaderFactory can produce a MetadataReader,这个Reader的作用就是读取类的元数据,包括Class相关的信息,比如是否接口、是否抽象类、是否有注解等等,以及获得注解相关的元数据,比如加了哪些注解等等,在整个Bean的生命周期中起到了非常重要的作用

After the register method is executed, the configureConfigurationClassPostProcessor method is called.

private void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {
    
    
        try {
    
    
        BeanDefinition definition = registry.getBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor");
        definition.getPropertyValues().add("metadataReaderFactory", new RuntimeBeanReference("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"));
    } catch (NoSuchBeanDefinitionException var3) {
    
    
        ;
    }
}

First obtain the BeanDefinition named internalConfigurationAnnotationProcessor from the container, and then set the metadataReaderFactory generated above to its properties.

When creating a new Spring container, a BeanDefinitionReader will be initialized. During the initialization process of this Reader, a ConfigurationClassPostProcessor will be registered in the container. The name is the above internalConfigurationAnnotationProcessor. It is the starting point for the Spring container to complete the scan, including @Component and @Configuration. The processing is all performed in this class, and to complete these tasks, it is natural to parse the metadata of each class, so it assigns the metadataReaderFactory to the properties of ConfigurationClassPostProcessor, which will be used to complete the metadata parsing of some beans later.

3、ContextIdApplicationContextInitializer

Initialize the container ID. The purpose of this class is to set an ID for the container, which is actually our project name. Get the application name configured by the property spring.application.name. If it does not exist, application will be used by default.

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
    
    
    //获取并设置容器ID
    ContextId contextId = getContextId(applicationContext);
    applicationContext.setId(contextId.getId());
    //容器beanFactory中注册一个名称为ContextId类名
    //值为contextId的bean
    applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(),
            contextId);
}

The first line first obtains a container ID object, then sets the ID attribute to the container, and registers the ID object as a singleton Bean to the container's singleton pool. Let's see how this ContextId comes from, and enter the getContextId method
.

//获取ContextID
private ContextId getContextId(ConfigurableApplicationContext applicationContext) {
    
    
    //父容器获取spring.application.name对应的bean
    ApplicationContext parent = applicationContext.getParent();
    if (parent != null && parent.containsBean(ContextId.class.getName())) {
    
    
        return parent.getBean(ContextId.class).createChildId();
    }
    //父容器获取不到,则生成一个contextId
    return new ContextId(getApplicationId(applicationContext.getEnvironment()));
}

If there is a parent container, create a child container ID based on the ID of the parent container. The format is parent container ID - child container serial number.

ContextIdApplicationContextInitializer.ContextId createChildId() {
    
    
    return ContextIdApplicationContextInitializer.this.new ContextId(this.id + "-" + this.children.incrementAndGet());
}

If there is no parent container, go to the environment and get the spring.application.name attribute. If there is no configuration, it defaults to application.

//获取应用ID
private String getApplicationId(ConfigurableEnvironment environment) {
    
    
    //获取属性:spring.application.name
    String name = environment.getProperty("spring.application.name");
    //如果为空,默认名application
    return StringUtils.hasText(name) ? name : "application";
}

Pass the obtained result as a parameter to the constructor of ContextId

 //ContextId类
class ContextId {
    
    
    //原子Long类
    private final AtomicLong children = new AtomicLong(0);

    private final String id;

    ContextId(String id) {
    
    
        this.id = id;
    }

    ContextId createChildId() {
    
    
        //线程安全递增
        return new ContextId(this.id + "-" + this.children.incrementAndGet());
    }

    String getId() {
    
    
        return this.id;
    }
}

That is to say, by default, this ContextId stores our project name and then sets it to the container.

4、ConfigurationWarningsApplicationContextInitializer

Configure alarm initializer ( 通过分析源码实际情况,默认扫描启动类所在的路径(或者@ComponentScan注解指定的路径)如果系统配置包扫描到了org或者org.springframework包就会发出警告打印warn日志并停止系统启动)

Insert image description here
ConfigurationWarningsApplicationContextInitializer initializer source code is as follows:

public class ConfigurationWarningsApplicationContextInitializer
		implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    

	private static final Log logger = LogFactory.getLog(ConfigurationWarningsApplicationContextInitializer.class);
	//初始化方法会在容器启动时调用,并将ConfigurationWarningsPostProcessor后置处理器注入到应用上下文中
	@Override
	public void initialize(ConfigurableApplicationContext context) {
    
    
		context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
	}

	/**
	 * 返回有问题的扫描包(@ComponentScan)Check对象
	 * @return the checks to apply
	 */
	protected Check[] getChecks() {
    
    
		return new Check[] {
    
     new ComponentScanPackageCheck() };
	}
}

ComponentScanPackageCheck is an internal class of ConfigurationWarningsApplicationContextInitializer, source code analysis

/**
* 可以应用的单一检查
 */
@FunctionalInterface
protected interface Check {
    
    

	/**
	 * 返回检查结果,如果检查失败,则返回警告,如果没有问题,则返回null
	 * @param registry the {@link BeanDefinitionRegistry}
	 * @return a warning message or {@code null}
	 */
	String getWarning(BeanDefinitionRegistry registry);

}

/**
 * 检查@ComponentScan注解扫描有问题的包
 */
protected static class ComponentScanPackageCheck implements Check {
    
    

	private static final Set<String> PROBLEM_PACKAGES;
	//定义扫描有问题的包
	static {
    
    
		Set<String> packages = new HashSet<>();
		packages.add("org.springframework");
		packages.add("org");
		PROBLEM_PACKAGES = Collections.unmodifiableSet(packages);
	}
	
	//检查@ComponentScan注解扫描的包是否有问题,如果有,则返回警告,否则返回null
	@Override
	public String getWarning(BeanDefinitionRegistry registry) {
    
    
     //获取@ComponentScan注解扫描的包集合
		Set<String> scannedPackages = getComponentScanningPackages(registry);
     //获取有问题的扫描包集合
		List<String> problematicPackages = getProblematicPackages(scannedPackages);
		if (problematicPackages.isEmpty()) {
    
    
			return null;
		}
		return "Your ApplicationContext is unlikely to start due to a @ComponentScan of "
				+ StringUtils.collectionToDelimitedString(problematicPackages, ", ") + ".";
	}
	
	//获取@ComponentScan注解扫描的包
	protected Set<String> getComponentScanningPackages(BeanDefinitionRegistry registry) {
    
    
		Set<String> packages = new LinkedHashSet<>();
     //获取容器中所有bean定义名称
		String[] names = registry.getBeanDefinitionNames();
		for (String name : names) {
    
    
       //获取name对应的bean定义对象
			BeanDefinition definition = registry.getBeanDefinition(name);
			if (definition instanceof AnnotatedBeanDefinition) {
    
    
				AnnotatedBeanDefinition annotatedDefinition = (AnnotatedBeanDefinition) definition;
				addComponentScanningPackages(packages, annotatedDefinition.getMetadata());
			}
		}
		return packages;
	}
	
	//将bean实例上注解@ComponentScan扫描包
	private void addComponentScanningPackages(Set<String> packages, AnnotationMetadata metadata) {
    
    
		AnnotationAttributes attributes = AnnotationAttributes
				.fromMap(metadata.getAnnotationAttributes(ComponentScan.class.getName(), true));
		if (attributes != null) {
    
    
			addPackages(packages, attributes.getStringArray("value"));
			addPackages(packages, attributes.getStringArray("basePackages"));
			addClasses(packages, attributes.getStringArray("basePackageClasses"));
			if (packages.isEmpty()) {
    
    
				packages.add(ClassUtils.getPackageName(metadata.getClassName()));
			}
		}
	}

	private void addPackages(Set<String> packages, String[] values) {
    
    
		if (values != null) {
    
    
			Collections.addAll(packages, values);
		}
	}

	private void addClasses(Set<String> packages, String[] values) {
    
    
		if (values != null) {
    
    
			for (String value : values) {
    
    
				packages.add(ClassUtils.getPackageName(value));
			}
		}
	}
	
	//获取有问题的扫描包集合,即包名是:org或org.springframework
	private List<String> getProblematicPackages(Set<String> scannedPackages) {
    
    
		List<String> problematicPackages = new ArrayList<>();
		for (String scannedPackage : scannedPackages) {
    
    
       //判定包名是否有问题,即包名是:org或org.springframework
			if (isProblematicPackage(scannedPackage)) {
    
    
				problematicPackages.add(getDisplayName(scannedPackage));
			}
		}
		return problematicPackages;
	}
	//判定包名是否有问题,即包名是:org或org.springframework
	private boolean isProblematicPackage(String scannedPackage) {
    
    
		if (scannedPackage == null || scannedPackage.isEmpty()) {
    
    
			return true;
		}
		return PROBLEM_PACKAGES.contains(scannedPackage);
	}

	private String getDisplayName(String scannedPackage) {
    
    
		if (scannedPackage == null || scannedPackage.isEmpty()) {
    
    
			return "the default package";
		}
		return "'" + scannedPackage + "'";
	}
}

Finally, the following log is printed on the console

** WARNING ** : Your ApplicationContext is unlikely to start due to a @ComponentScan of 'org'.

This only prints a line of logs and does not stop the program. However, after actual testing, the program cannot be started normally. This path is the package path of the Spring framework itself. Scanning this package will interfere with the normal execution process of Spring and fall into a loop. Of course, this is normal. The path of our project will not be defined this way.

5、ServerPortInfoApplicationContextInitializer

The service port initializer implements the ApplicationContextInitializer and ApplicationListener interfaces respectively, adds the event listener this to the applicationContext, listens to the WebServerInitializedEvent event, and configures the port number of the service.

public class ServerPortInfoApplicationContextInitializer
        implements ApplicationContextInitializer<ConfigurableApplicationContext>,
        ApplicationListener<WebServerInitializedEvent> {
    
    

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
    
    
        //把this添加到Application的listener中
        applicationContext.addApplicationListener(this);
    }
    
    //监听处理WebServerInitializedEvent事件
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
    
    
        //获取environment中配置的server.ports
        String propertyName = "local." + getName(event.getApplicationContext()) + ".port";
        setPortProperty(event.getApplicationContext(), propertyName,
                event.getWebServer().getPort());
    }
}

6、ConditionEvaluationReportLoggingListener

The main function of the condition evaluation log listener is to add a ConditionEvaluationReportListener listener to the applicationContext. The ConditionEvaluationReportListener listens to the ContextRefreshedEvent and ApplicationFailedEvent events and prints the corresponding logs.

public class ConditionEvaluationReportLoggingListener
        implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
    
    
        this.applicationContext = applicationContext;
        //applicationContext中添加一个ConditionEvaluationReportListener
        applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
        if (applicationContext instanceof GenericApplicationContext) {
    
    
            //注册一个ConditionEvaluationReport bean
            this.report = ConditionEvaluationReport
                    .get(this.applicationContext.getBeanFactory());
        }
    }
}

First add a listener ConditionEvaluationReportListener to the container's listener list. This class is its internal class. The event types of interest are specified as ContextRefreshedEvent and ApplicationFailedEvent through the supportsEventType method.

private class ConditionEvaluationReportListener implements GenericApplicationListener {
    
    
    private ConditionEvaluationReportListener() {
    
    
    }
......
......
    public boolean supportsEventType(ResolvableType resolvableType) {
    
    
        Class<?> type = resolvableType.getRawClass();
        if (type == null) {
    
    
            return false;
        } else {
    
    
            return ContextRefreshedEvent.class.isAssignableFrom(type) || ApplicationFailedEvent.class.isAssignableFrom(type);
        }
    }
    ......
}

We will analyze the specific handling of these two events later when we talk about specific events.

Then in the if branch below, the current Spring container type is AnnotationConfigServletWebServerApplicationContext, which is a subclass of GenericApplicationContext, so it will enter the if branch and call the get method of ConditionEvaluationReport

//用于记录Condition注解的评估情况
public final class ConditionEvaluationReport {
    
    

    //bean名称为autoConfigurationReport
    //类型为ConditionEvaluationReport
    private static final String BEAN_NAME = "autoConfigurationReport";
    
    //从beanFactory中获取ConditionEvaluationReport实例
    public static ConditionEvaluationReport get(
            ConfigurableListableBeanFactory beanFactory) {
    
    
        synchronized (beanFactory) {
    
    
            ConditionEvaluationReport report;
            if (beanFactory.containsSingleton(BEAN_NAME)) {
    
    
                //如果bean已经被注册,立即返回
                report = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);
            }
            else {
    
    
                //否则注册bean
                report = new ConditionEvaluationReport();
                beanFactory.registerSingleton(BEAN_NAME, report);
            }
            locateParent(beanFactory.getParentBeanFactory(), report);
            return report;
        }
    }
}

First, go to the container to find the singleton bean named autoConfigurationReport. If there is not one, create a new one and store it in the container's singleton pool. Then call the locateParent method. If the parent container exists, check whether there is a singleton named autoConfigurationReport in the parent container. Example Bean, if available, set the Report in the parent container to the parent property of the current Report

 private static void locateParent(BeanFactory beanFactory, ConditionEvaluationReport report) {
    
    
        if (beanFactory != null && report.parent == null && beanFactory.containsBean("autoConfigurationReport")) {
    
    
            report.parent = (ConditionEvaluationReport)beanFactory.getBean("autoConfigurationReport", ConditionEvaluationReport.class);
        }
    }

The function of ConditionEvaluationReport is to print some DEBUG logs of matching results during the SpringBoot automatic configuration process, including which classes have completed automatic configuration, which classes have not met which conditions and failed to load, etc., such as in the figure below

============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:
-----------------

   CodecsAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer' (OnClassCondition)

   CodecsAutoConfiguration.JacksonCodecConfiguration matched:
      - @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition)
      ......
      ......
      ......

Negative matches:
-----------------

   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)

   AopAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.aspectj.lang.annotation.Aspect' (OnClassCondition)
       ......
       ......
       ......

7、RSocketPortInfoApplicationContextInitializer

Added a listener for the RSocketServerInitializedEvent event to the ApplicationContext.

public class RSocketPortInfoApplicationContextInitializer
		implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    

	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
    
    
		/**
		  * 注入一个端口检查和设置的监听器,对应的事件RSocketServerInitializedEvent
		  **/
		applicationContext.addApplicationListener(new Listener(applicationContext));
	}
    
    //这里直接写了个内部类实现RSocketServerInitializedEvent事件的监听
	private static class Listener implements ApplicationListener<RSocketServerInitializedEvent> {
    
    

		private static final String PROPERTY_NAME = "local.rsocket.server.port";

		private final ConfigurableApplicationContext applicationContext;

		Listener(ConfigurableApplicationContext applicationContext) {
    
    
			this.applicationContext = applicationContext;
		}

		@Override
		public void onApplicationEvent(RSocketServerInitializedEvent event) {
    
    
			if (event.getServer().address() != null) {
    
    
				setPortProperty(this.applicationContext, event.getServer().address().getPort());
			}
		}

		private void setPortProperty(ApplicationContext context, int port) {
    
    
			if (context instanceof ConfigurableApplicationContext) {
    
    
				setPortProperty(((ConfigurableApplicationContext) context).getEnvironment(), port);
			}
			if (context.getParent() != null) {
    
    
				setPortProperty(context.getParent(), port);
			}
		}

		private void setPortProperty(ConfigurableEnvironment environment, int port) {
    
    
			MutablePropertySources sources = environment.getPropertySources();
			PropertySource<?> source = sources.get("server.ports");
			if (source == null) {
    
    
				source = new MapPropertySource("server.ports", new HashMap<>());
				sources.addFirst(source);
			}
			setPortProperty(port, source);
		}

		@SuppressWarnings("unchecked")
		private void setPortProperty(int port, PropertySource<?> source) {
    
    
			((Map<String, Object>) source.getSource()).put(PROPERTY_NAME, port);
		}

	}

}

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.

Supongo que te gusta

Origin blog.csdn.net/weixin_49114503/article/details/132132808
Recomendado
Clasificación