从最开始SpringApplication初始化的时候,我们就可以看到Spring加载了7个执行器实例存起来,然后SpringApplication启动过程中的准备上下文环境,这7个执行器将以此执行其初始化方法,下面我们来分别看看这7个初始化方法都干了什么:
@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
自己,那岂不是陷入死循环了?
我去果然,不过只要不像我这样傻的都不会干这个事。
可以看到这个地方是通过在环境里面配置context.initializer.classes
来定义初始化class的,所以我们可以在配置文件里面定义初始化类。
注意
Assert.isAssignable(ApplicationContextInitializer.class, initializerClass);
还有,这个时候还没有初始化我们交给spring管理的bean,这个时候是拿不到bean的。
看下ConfigurationClassPostProcessor和CachingMetadataReaderFactoryPostProcessor的注释呢:
好像有点核心,继续看下这个初始化器的初始化过程。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new CachingMetadataReaderFactoryPostProcessor());
}
在往下看,返现这个初始化器貌似就是给上下文设置了一个BeanFactoryPostProcessor。
看下BeanFactoryPostProcessor的注释:
这个注释翻译器翻译出来的太差了,我用蹩脚英语大概理解了下,这个初始化器貌似就是依据 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";
}
怎么感觉跟刚才的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 {
@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事件是什么事件:
估计在刷新应用程序时会遇到这个事件。到时候再看。
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(this);
}
又是给上下文里面添加监听器。没什么逻辑,后面再看。
@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实例,以便在上下文加载失败的时候写日志。