spring boot源码解析(二)

前言

上篇我们介绍了SpringApplication.run过程包含的大致内容,这篇我们细节讲下run里面的SpringApplicationRunListeners过程。
在这里插入图片描述
从代码我们可以看到listeners的主要使用或引用的点:

  1. getRunListeners
  2. starting
  3. prepareEnvironment
  4. prepareContext
  5. started
  6. handleRunFailure
  7. 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的加载和触发过程。

猜你喜欢

转载自blog.csdn.net/caohao1210/article/details/88573749