前言
上篇我们介绍了SpringApplication.run过程包含的大致内容,这篇我们细节讲下run里面的SpringApplicationRunListeners过程。
从代码我们可以看到listeners的主要使用或引用的点:
- getRunListeners
- starting
- prepareEnvironment
- prepareContext
- started
- handleRunFailure
- running
我们挨个分析,首先SpringApplicationRunListeners是干什么的,其实通过上篇大致应该能猜到,或者通过SpringApplicationRunListener接口能猜到,可以简单的理解成spring application 启动过程的监听(SpringApplicationRunListener),而SpringApplicationRunListeners则是出发这些监听的执行者。
SpringApplicationRunListener接口
首先我们看下SpringApplicationRunListener接口:
public interface SpringApplicationRunListener {
void starting();
void environmentPrepared(ConfigurableEnvironment environment);
void contextPrepared(ConfigurableApplicationContext context);
void contextLoaded(ConfigurableApplicationContext context);
void started(ConfigurableApplicationContext context);
void running(ConfigurableApplicationContext context);
void failed(ConfigurableApplicationContext context, Throwable exception);
}
可以看出listener的过程主要就分为:启动中、environment预处理、context预处理、context加载完成、启动完成、运行中、失败几个过程。
SpringApplicationRunListeners代码比较简单,这里就不贴了,主要就是组合模式的将SpringApplicationRunListener集合组合,然后循环调用,当然failed的方法而外加了一层异常捕获和日志打印。
getRunListeners 方法
回到正题,getRunListeners初始化构造SpringApplicationRunListeners对象,在方法中我们可以看到主要调用getSpringFactoriesInstances获取所有的SpringApplicationRunListener实现。(注:getSpringFactoriesInstances这个方法用到的地方比较多,会详细介绍一下。)
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
getSpringFactoriesInstances 方法
把几个方法揉在一起看,更容易理解:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
//类加载器
ClassLoader classLoader = getClassLoader();
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
//类全程(接口)
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//拿到所有的META-INF/spring.factories文件url
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
首先看getSpringFactoriesInstances方法的传入参数,type:表示接口,parameterTypes表示参数类型,后面紧跟与之对应的参数。
可以看到方法中调用了SpringFactoriesLoader.loadFactoryNames方法,该方法可以看出其实就是加载了所有的META-INF/spring.factories文件,然后组合成一个map,而这个map保存着接口和实现类的名称。这里其实非常像SPI机制,算是一种变种的SPI机制。
从SpringFactoriesLoader.loadFactoryNames方法后拿到了接口所有的实现类全名,然后调用createSpringFactoriesInstances,其实就是通过实现类全名构造实例,最后进行一个排序,返回。
通过createSpringFactoriesInstances方法我们可以发现,通过parameterTypes获取对应的参数构造方法,然后进行参数传入构造,所以这里有个点很关键,即:所有的接口实现都需要同样的构造方法,这是接口层面无法约束的。
排序在spring里面经常出现,spring中有大量的这种一个接口对应很多实现,然后进行顺序调用,所以这个点是通用的,spring中的顺序主要由实现Ordered接口(PriorityOrdered)或Order注解来控制顺序。
EventPublishingRunListener
我们可以看到除了初始化,其他的SpringApplicationRunListeners调用的方法穿插在run启动方法中,所以这里无需再多介绍什么。这里我们开始介绍debug时,我们能看到SpringApplicationRunListener的实现EventPublishingRunListener类,它的整个所有接口方法实现,具体做了哪些操作。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
this.application, this.args, context));
}
@Override
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));
}
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(
new ApplicationStartedEvent(this.application, this.args, context));
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(
new ApplicationReadyEvent(this.application, this.args, context));
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application,
this.args, context, exception);
if (context != null && context.isActive()) {
context.publishEvent(event);
}
else {
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
private static class LoggingErrorHandler implements ErrorHandler {
private static Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
}
从代码可以看出,实现了SpringApplicationRunListener和Ordered,Ordered为排序用的,可以看到返回的是0。数字越小,优先级越大。
从starting、environmentPrepared、contextPrepared、contextLoaded用的是SimpleApplicationEventMulticaster.multicastEvent进行处理,而started、running、failed使用的是ConfigurableApplicationContext.publishEvent,但接收的参数都是ApplicationEvent的实现类,区别在于什么呢?
从EventPublishingRunListener构造方法我们可以看到,构造SimpleApplicationEventMulticaster类对象以后,将SpringApplication中的所有ApplicationListener都赋给了SimpleApplicationEventMulticaster对象,而ConfigurableApplicationContext是参数传入进来的context对象。
SimpleApplicationEventMulticaster
构造方法为空,所以没有什么需要看的
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized(this.retrievalMutex) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
addApplicationListener方法,可以看出用了sych保证线程安全,将listener放入ListenerRetriever中,前面有一段AOP操作,暂时不确定其意,猜测是判断是否是AOP切面扩展接口的实现
从EventPublishingRunListener的starting、environmentPrepared、contextPrepared、contextLoaded可以看到主要内容即调用multicastEvent(contextLoaded在调用之前,还进行了ApplicationContextAware接口实现判定,可以看到contextLoaded状态触发的监听可以实现ApplicationContextAware获取到ApplicationContext),构造的Event都是对应状态的Event。
public void multicastEvent(ApplicationEvent event) {
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
从multicastEvent方法实现来看,其中调用了通过event获取resolvableType,过去方式这里不贴代码了,大致理解即:通过event实现了ResolvableTypeProvider接口,然后直接调用getResolvableType方法获取,还一种通过class类名包装一个。似乎从上述的几个方法中的ApplicationEvent都没有实现ResolvableTypeProvider接口,即都是通过class包装的。
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor();
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
}
}
反编译的代码,跟源码存在一定的差异,但目的是一样的,可以看到通过通过传入evenType(事件类型)获取对应的监听,这个是从实现的监听eventType来判断的,然后遍历调动listener实现的onApplicationEvent方法。(注:可以看到获取对应的listener时,除了传入了eventType,也传入了ApplicationEvent,从getApplicationListeners方法实现可以看出,传入ApplicationEvent对象实际是为了拿到sourceType,即:springApplication,可能对于某些listener只在某些模式启动才生效,比如:在spring boot下不生效,在spring mvc中生效,限定了启动source类。)
AbstractApplicationContext
从started、running、failed方法来看,都是调用 AbstractApplicationContext.publishEvent方法,包括前面说到的如果我们实现自定义event和listener,也是需要通过context.publishEvent来触发。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
Object applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent)event;
} else {
applicationEvent = new PayloadApplicationEvent(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
}
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
这部分代码可以从三部分理解,第一部分判断event类型,是否需要包装成payload
第二部分判断是不是prepareRefresh过程,如果是prepareRefresh过程,event不会直接调用监听通知,而是先保存在earlyApplicationEvents集合中,等到registerListeners的时候再触发,所以这里实际还是调用了SimpleApplicationEventMulticaster的multicastEvent方法(虽然是同样的方法,但对应的SimpleApplicationEventMulticaster对象并非同一个,里面的applicationListeners也不一样,这里在哪构造的后面再分析。)。
第三部分,判断参数parent,从参数来看是构造方法传入的,如果存在即调用parent的publishEvent的方法。从这里来看应该是支持上层继承然后引用具体的实现,可能是方面上层使用装饰器模式扩展。但比较奇怪的是为什么这个放在第二部之后,也就是说即调用了SimpleApplicationEventMulticaster.multicastEvent,同时也调用parent.publishEvent,这里可能要注意防止多次触发listener。
总结
本篇把SpringApplicationRunListeners、SpringApplicationRunListener、ApplicationListener以及核心逻辑类SimpleApplicationEventMulticaster关系从源码层面分析了一下,大致清楚了spring启动过程对listener的加载和触发过程。