前面我们讲了spring boot在run()方法的启动流程中,通过SpringApplicationRunListeners来手动执行不同阶段时的监听器回调,那里调用到的监听器都是ApplicationListener类型,这些监听器做的事情能解答我们使用spring boot的很多现象。
SpringBoot通过事件机制来完成启动流程执行,这样能够方便扩展。 在org.springframework.boot.SpringApplication类中有一个成员变量:
public class SpringApplication {
...
private List<ApplicationListener<?>> listeners;
...
}
org.springframework.context.ApplicationListener 这里使用@FunctionalInterface注解来约束函数式接口定义,ApplicationListener是一个泛型接口,泛型用于接受不同类型的事件。需要了解的是,ApplicationListener的实现类非常多,足以说明这个事件监听机制使用的范围之广。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
可以看到,很多第三方的组件都去实现了ApplicationListener。
一、ApplicationListener的获取
这里的逻辑总结来说就是从classpath下META-INF/spring.factories文件里配置的ApplicationListener,具体的读取逻辑在方法: org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames() 具体逻辑有需要的时候可以再去研究。这里就读取了一部分ApplicationListener,是spring boot启动必须的监听器,同时需要注意的是,这个动作是在SpringApplication()构造方法里完成的,此时还没有执行run()方法。
public class SpringApplication {
...
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
...
}
二、ApplicationListener的调用
ApplicationListener注册后,调用的地方在run()方法里,通过SpringApplicationRunListeners ->?EventPublishingRunListener ->?SimpleApplicationEventMulticaster ->?ApplicationListener 这条链路调用到具体的监听器。
三、BootstrapApplicationListener
在org.springframework.context.ApplicationListener众多实现者有一个非常重要的实现就是 org.springframework.cloud.bootstrap.BootstrapApplicationListener 可以看到,ApplicationListener是定义在spring-context包中,属于经典上下文范畴,BootstrapApplicationListener是在spring-cloud-context中,属于cloud上线文范畴。 官方解释: 这个listener会prepare SpringApplication(例如填充他的Environment等),通过代理给在独立的bootstrap context里的ApplicationContextInitializer beans。bootstrap context 是SpringApplication从spring.factories中BootstrapConfiguration中创建的,从bootstrap.properties(or yml)而不是普通的application.properties(or yml)初始化的。
BootstrapApplicationListener执行后会创建一个id=bootstrap的上下文,这个上下文不是一个独立的父上下文,不是装载应用bean的上下文。
public class BootstrapApplicationListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
true)) {
return;
}
// don't listen to events in a bootstrap context
if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
return;
}
ConfigurableApplicationContext context = null;
String configName = environment
.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
.getInitializers()) {
if (initializer instanceof ParentContextApplicationContextInitializer) {
context = findBootstrapContext(
(ParentContextApplicationContextInitializer) initializer,
configName);
}
}
if (context == null) {
context = bootstrapServiceContext(environment, event.getSpringApplication(),
configName);
event.getSpringApplication()
.addListeners(new CloseContextOnFailureApplicationListener(context));
}
apply(context, event.getSpringApplication(), environment);
}
}
整个回调方法通过开关控制
spring.cloud.bootstrap.enabled
这里通过执行org.springframework.boot.SpringApplication#run(java.lang.String...)来生成ApplicationContext。
|