跟我一起阅读SpringBoot源码(九)——初始化执行器

从最开始SpringApplication初始化的时候,我们就可以看到Spring加载了7个执行器实例存起来,然后SpringApplication启动过程中的准备上下文环境,这7个执行器将以此执行其初始化方法,下面我们来分别看看这7个初始化方法都干了什么:

DelegatingApplicationContextInitializer

跟我一起阅读SpringBoot源码(九)——初始化执行器_第1张图片

@Override
	public void initialize(ConfigurableApplicationContext context) {
		ConfigurableEnvironment environment = context.getEnvironment();
		List> initializerClasses = getInitializerClasses(environment);
		if (!initializerClasses.isEmpty()) {
			applyInitializerClasses(context, initializerClasses);
		}
	}

我们先看getInitializerClasses,该方法用于获取自定义的初始化器。可以看到先从context.initializer.classes获取到配置的类名,多个类名用逗号分隔开,然后再执行getInitializerClass去加载类。注意断言Assert.isAssignable(ApplicationContextInitializer.class, initializerClass);我们配置的initializer必须是ApplicationContextInitializer的实现类才行。

	private static final String PROPERTY_NAME = "context.initializer.classes";
	
	private List> getInitializerClasses(ConfigurableEnvironment env) {
		String classNames = env.getProperty(PROPERTY_NAME);
		List> classes = new ArrayList<>();
		if (StringUtils.hasLength(classNames)) {
			for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
				classes.add(getInitializerClass(className));
			}
		}
		return classes;
	}
	
	private Class getInitializerClass(String className) throws LinkageError {
		try {
			Class initializerClass = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader());
			Assert.isAssignable(ApplicationContextInitializer.class, initializerClass);
			return initializerClass;
		}
		catch (ClassNotFoundException ex) {
			throw new ApplicationContextException("Failed to load context initializer class [" + className + "]", ex);
		}
	}
	
	private ApplicationContextInitializer instantiateInitializer(Class contextClass, Class initializerClass) {
		Class requireContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
				ApplicationContextInitializer.class);
		Assert.isAssignable(requireContextClass, contextClass,
				String.format(
						"Could not add context initializer [%s] as its generic parameter [%s] is not assignable "
								+ "from the type of application context used by this context loader [%s]: ",
						initializerClass.getName(), requireContextClass.getName(), contextClass.getName()));
		return (ApplicationContextInitializer) BeanUtils.instantiateClass(initializerClass);
	}

获取到我们自己定义的初始化器实例后,执行applyInitializers操作。

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

这个地方就很坏了,我们如果在context.initializer.classes配的就是org.springframework.boot.context.config.DelegatingApplicationContextInitializer自己,那岂不是陷入死循环了?
跟我一起阅读SpringBoot源码(九)——初始化执行器_第2张图片
我去果然,不过只要不像我这样傻的都不会干这个事。

可以看到这个地方是通过在环境里面配置context.initializer.classes来定义初始化class的,所以我们可以在配置文件里面定义初始化类。

注意Assert.isAssignable(ApplicationContextInitializer.class, initializerClass);
还有,这个时候还没有初始化我们交给spring管理的bean,这个时候是拿不到bean的。

SharedMetadataReaderFactoryContextInitializer

跟我一起阅读SpringBoot源码(九)——初始化执行器_第3张图片
看下ConfigurationClassPostProcessor和CachingMetadataReaderFactoryPostProcessor的注释呢:
跟我一起阅读SpringBoot源码(九)——初始化执行器_第4张图片
跟我一起阅读SpringBoot源码(九)——初始化执行器_第5张图片

好像有点核心,继续看下这个初始化器的初始化过程。

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

在往下看,返现这个初始化器貌似就是给上下文设置了一个BeanFactoryPostProcessor。
看下BeanFactoryPostProcessor的注释:
跟我一起阅读SpringBoot源码(九)——初始化执行器_第6张图片

ContextIdApplicationContextInitializer

这个注释翻译器翻译出来的太差了,我用蹩脚英语大概理解了下,这个初始化器貌似就是依据 spring.application.name属性来设置Spring的id,如果这个属性没有设置,那么默认的就是application。

/**
 * {@link ApplicationContextInitializer} that sets the Spring
 * {@link ApplicationContext#getId() ApplicationContext ID}. The
 * {@code spring.application.name} property is used to create the ID. If the property is
 * not set {@code application} is used.
 *
 * @author Dave Syer
 * @author Andy Wilkinson
 * @since 1.0.0
 */

看下注释应该大概知道执行了什么了。

	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		ContextId contextId = getContextId(applicationContext);
		applicationContext.setId(contextId.getId());
		applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId);
	}
	private ContextId getContextId(ConfigurableApplicationContext applicationContext) {
		ApplicationContext parent = applicationContext.getParent();
		if (parent != null && parent.containsBean(ContextId.class.getName())) {
			return parent.getBean(ContextId.class).createChildId();
		}
		return new ContextId(getApplicationId(applicationContext.getEnvironment()));
	}
	//这里吐槽下,spring项目成员都在用魔法值(并无其他什么意思)
	private String getApplicationId(ConfigurableEnvironment environment) {
		String name = environment.getProperty("spring.application.name");
		return StringUtils.hasText(name) ? name : "application";
	}

ConfigurationWarningsApplicationContextInitializer

跟我一起阅读SpringBoot源码(九)——初始化执行器_第7张图片
怎么感觉跟刚才的SharedMetadataReaderFactoryContextInitializer差不多呢

	@Override
	public void initialize(ConfigurableApplicationContext context) {
		context.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));
	}
	/**
	 * {@link BeanDefinitionRegistryPostProcessor} to report warnings.
	 */
	protected static final class ConfigurationWarningsPostProcessor
			implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {

跟我一起阅读SpringBoot源码(九)——初始化执行器_第8张图片
就先不多说了,看下一个初始化器。

RSocketPortInfoApplicationContextInitializer

跟我一起阅读SpringBoot源码(九)——初始化执行器_第9张图片
翻译过来有点难懂,看下他的初始化过程吧:

	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		applicationContext.addApplicationListener(new Listener(applicationContext));
	}
	
	//这里直接写了个内部类实现RSocketServerInitializedEvent事件的监听
	private static class Listener implements ApplicationListener {

		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) {
			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) source.getSource()).put(PROPERTY_NAME, port);
		}

	}

RSocketServerInitializedEvent

看下RSocketServerInitializedEvent事件是什么事件:
跟我一起阅读SpringBoot源码(九)——初始化执行器_第10张图片
估计在刷新应用程序时会遇到这个事件。到时候再看。

ServerPortInfoApplicationContextInitializer

跟我一起阅读SpringBoot源码(九)——初始化执行器_第11张图片

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
	applicationContext.addApplicationListener(this);
}

又是给上下文里面添加监听器。没什么逻辑,后面再看。

ConditionEvaluationReportLoggingListener

看名字好像又是侦听器,头大
跟我一起阅读SpringBoot源码(九)——初始化执行器_第12张图片

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

这个侦听器用于写日志的,对于通用型应用上下文先行获取report实例,以便在上下文加载失败的时候写日志。

你可能感兴趣的:(Spring,spring,spring,boot)