SpringBoot源码(二): SpringApplicationRunListeners.starting()

介绍

上一章介绍了springBoot启动时候,还未运行run方法时的初始化。现在继续介绍run方法的内容。

下面就是run方法的所有内容了,接下来会分步去介绍各个类和方法的作用。

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, exceptionReporters, ex);
			throw new IllegalStateException(ex);
		}
		listeners.running(context);
		return context;
	}

 

StopWatch

stopWatch是一个计数器,通过源码发现,就是在程序运行时候start,在停止时候stop。然后拿到totalTimeMillis就是程序的启动时间。我们也可以自己去使用,他也提供了优雅的打印方法 prettyPrint();

 

	public void start(String taskName) throws IllegalStateException {
		if (this.currentTaskName != null) {
			throw new IllegalStateException("Can't start StopWatch: it's already 
        running");
		}
		this.currentTaskName = taskName;
		this.startTimeMillis = System.currentTimeMillis();
	}

	/**
	 * Stop the current task. The results are undefined if timing
	 * methods are called without invoking at least one pair
	 * {@code start()} / {@code stop()} methods.
	 * @see #start()
	 */
	public void stop() throws IllegalStateException {
		if (this.currentTaskName == null) {
			throw new IllegalStateException("Can't stop StopWatch: it's not running");
		}
		long lastTime = System.currentTimeMillis() - this.startTimeMillis;
		this.totalTimeMillis += lastTime;
		this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
		if (this.keepTaskList) {
			this.taskList.add(this.lastTaskInfo);
		}
		++this.taskCount;
		this.currentTaskName = null;
	}


	public String prettyPrint() {
		StringBuilder sb = new StringBuilder(shortSummary());
		sb.append('\n');
		if (!this.keepTaskList) {
			sb.append("No task info kept");
		}
		else {
			sb.append("-----------------------------------------\n");
			sb.append("ms     %     Task name\n");
			sb.append("-----------------------------------------\n");
			NumberFormat nf = NumberFormat.getNumberInstance();
			nf.setMinimumIntegerDigits(5);
			nf.setGroupingUsed(false);
			NumberFormat pf = NumberFormat.getPercentInstance();
			pf.setMinimumIntegerDigits(3);
			pf.setGroupingUsed(false);
			for (TaskInfo task : getTaskInfo()) {
				sb.append(nf.format(task.getTimeMillis())).append("  ");
				sb.append(pf.format(task.getTimeSeconds() /             
            getTotalTimeSeconds())).append("  ");
				sb.append(task.getTaskName()).append("\n");
			}
		}
		return sb.toString();
	}

 

配置Headless

当程序运行没有外显设备,比如鼠标键盘等信息时候,依然运行程序。

	private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
				SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

 

SpringApplicationRunListeners

接下来就要介绍到SpringApplicationRunListeners了,我们知道springBoot在启动时候有很多的listener启动,去监听我们发送的事件进行处理。

那springBoot自己的listener是怎么产生监听的呢。主要就是靠这个SpringApplicationRunListeners,它主要是在springBoot启动时候使用,主要是如何作用的呢?直接看代码吧。

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// 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;
	}

getSpringFactoriesInstances 这个方法在上一节的时候,有想知道细节的小伙伴可以去看下上一章。主要作用就是通过SpringFactoriesLoader.loadFactoryNames方法,从META-INF/spring.fatcories中拿到SpringApplicationRunListener的具体的类,然后通过反射进行实例化,这里提一下这边在调用getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)时候, this就是这个springApplication作为参数传递,因为实例化时候构造参数需要,在后面的listener中用到。

通过spring-boot的META-INF/spring.fatcories的文件中拿到具体类信息。

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

然后我们去 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();
        // 把之前在初始化时候找到的ApplicationListener加到广播中
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

    /**
    
    暂时省略其他代码

    */

}

从构造函数中我们就看到了之前传入的springApplication。

这里先创建一个event的广播,然后把之前在执行run方法之前初始化时候实例化的ApplicationListner放到广播中它的作用就是当有事件过来的时候,会去调用广播方法,然后轮训所有的listener,然后满足条件的(泛型,后面会介绍到),就调用这个listener的onApplicationEvent方法。

这边的处理方式是不是听着很熟悉。对的,他就是观察者模式。

像我们一般写的观察者,都是直接subject里面一个加list属性,提供一个register方法,把观察者注册进去。然后事件直接通过循环list的listener发送出去。

spring内部是通过一个ApplicationEventMulticaster进行了解耦,listener放进了这个广播中。我们通过调用这个多播器进行派发事件。

这样我们在用spring写事件的时候,即使不懂什么是观察者模式也没有关系,写好要发的事件;然后实现ApplicationListener写好listener后(spring4.2之后也可以直接在方法写@EventListener注解也可以,这个后面也会介绍)。通过applicationContext.publishEvent(event)发送出去之后,实现监听的listener直接就能接收到了。这样既不需要我们懂观察者模式,也不需要我们自己注册观察者,都由spring自己做好了。

 

SpringApplicationRunListeners.starting()

接下来按照SpringApplication的run方法的流程,继续向下看。接下来到SpringApplicationRunListeners的starting;

	public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	public void starting() {
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}

这边看就是调用EventPublishingRunListener的starting方法,然后调用广播发布ApplicationStartingEvent事件。 那spring的listener是如何分辨是自己该执行的事件呢?继续向代码中分析。

 

事件监听

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}


	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType         
        eventType) {
        // 封装事件类型
		ResolvableType type = (eventType != null ? eventType : 
        resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, 
            type)) 
            {
            // 判断有没有线程池
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
                // 执行listner
				invokeListener(listener, event);
			}
		}
	}

	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent         
        event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
                // listener调用执行事件方法
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass().getName()))         
                {
				// Possibly a lambda-defined listener which we could not resolve the 
                 generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isDebugEnabled()) {
					logger.debug("Non-matching event type for listener: " + listener, 
                    ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

通过上述代码发现拿到了listener之后就开始执行listener的对于事件的处理了,那对于listener的筛选在哪里呢?在 getApplicationListeners 这个方法中,那我们就来看看这个方法。

	protected Collection<ApplicationListener<?>> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
        
        // 拿到要发送的消息
		Object source = event.getSource();
        // 消息的类型
		Class<?> sourceType = (source != null ? source.getClass() : null);
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
        
		// 通过缓存查询
		ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
		if (retriever != null) {
			return retriever.getApplicationListeners();
		}
        
		if (this.beanClassLoader == null ||
				(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
						(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
			// 双重检查
			synchronized (this.retrievalMutex) {
				retriever = this.retrieverCache.get(cacheKey);
				if (retriever != null) {
					return retriever.getApplicationListeners();
				}
				retriever = new ListenerRetriever(true);
                // 根据消息的类型和事件的类型判断
				Collection<ApplicationListener<?>> listeners =
						retrieveApplicationListeners(eventType, sourceType, retriever);
				this.retrieverCache.put(cacheKey, retriever);
				return listeners;
			}
		}
		else {
			// 不需要缓存
			return retrieveApplicationListeners(eventType, sourceType, null);
		}
	}

再继续向下看retrieveApplicationListeners方法。

	private Collection<ApplicationListener<?>> retrieveApplicationListeners(
			ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable 
            ListenerRetriever retriever) {

		LinkedList<ApplicationListener<?>> allListeners = new LinkedList<>();
		Set<ApplicationListener<?>> listeners;
		Set<String> listenerBeans;
		synchronized (this.retrievalMutex) {
            // 在之前通过反射创建广播的时候,已经把SpringApplication的listener加进来了
			listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
			listenerBeans = new LinkedHashSet<> 
                                (this.defaultRetriever.applicationListenerBeans);
		}
		for (ApplicationListener<?> listener : listeners) {
            // 判断是否满足条件
			if (supportsEvent(listener, eventType, sourceType)) {
				if (retriever != null) {
					retriever.applicationListeners.add(listener);
				}
				allListeners.add(listener);
			}
		}
		if (!listenerBeans.isEmpty()) {
			BeanFactory beanFactory = getBeanFactory();
			for (String listenerBeanName : listenerBeans) {
				try {
					Class<?> listenerType = beanFactory.getType(listenerBeanName);
					if (listenerType == null || supportsEvent(listenerType, eventType)) {
						ApplicationListener<?> listener =
								beanFactory.getBean(listenerBeanName, 
                                             ApplicationListener.class);
						if (!allListeners.contains(listener) && supportsEvent(listener, 
                            eventType, sourceType)) {
							if (retriever != null) {
								retriever.applicationListenerBeans.add(listenerBeanName);
							}
							allListeners.add(listener);
						}
					}
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Singleton listener instance (without backing bean definition) 
                    // disappeared -
					// probably in the middle of the destruction phase
				}
			}
		}
		AnnotationAwareOrderComparator.sort(allListeners);
		return allListeners;
	}

还是没有看到具体是怎么判断listener如何满足的,继续看 supportsEvent(listener, eventType, sourceType) 的方法;

	protected boolean supportsEvent(
			ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> 
            sourceType) {
        // 判断是否是GenericApplicationListener,不然就创建适配器
		GenericApplicationListener smartListener = (listener instanceof 
        GenericApplicationListener ?  (GenericApplicationListener) listener : new 
                GenericApplicationListenerAdapter(listener));
		return (smartListener.supportsEventType(eventType) && 
               smartListener.supportsSourceType(sourceType));
	}

再看下创建适配器的方法,这边提一下ResolvableType 这个类,这个类是spring对于class的一个封装,通过这个类,可以拿到class的接口,继承类,以及泛型参数的信息。具体逻辑大家就自己看吧,不展开介绍了,后面应该会单独介绍这个类的。现在只需要知道,这边是根据listener的类型,然后向上找到ApplicationListener这个接口的泛型参数。


	public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
		Assert.notNull(delegate, "Delegate listener must not be null");
		this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
		this.declaredEventType = resolveDeclaredEventType(this.delegate);
	}


	@Nullable
	static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
		ResolvableType resolvableType = 
        ResolvableType.forClass(listenerType).as(ApplicationListener.class);
		return (resolvableType.hasGenerics() ? resolvableType.getGeneric() : null);
	}

	@Nullable
	private static ResolvableType 
        resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
		ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
		if (declaredEventType == null || declaredEventType.isAssignableFrom(
				ResolvableType.forClass(ApplicationEvent.class))) {
			Class<?> targetClass = AopUtils.getTargetClass(listener);
			if (targetClass != listener.getClass()) {
				declaredEventType = resolveDeclaredEventType(targetClass);
			}
		}
		return declaredEventType;
	}

拿到了listener的泛型参数之后,大家应该能想到是根据什么判断了吧?对的,就是根据Listener的泛型参数类型,和事件的类型(eventType)做比较。如果listener的泛型类型是事件类型(eventType)的接口或者超类,那就满足条件。直接看适配器代码逻辑吧。

    @Override
    public boolean supportsEventType(ResolvableType eventType) {
		if (this.delegate instanceof SmartApplicationListener) {
			Class<? extends ApplicationEvent> eventClass = (Class<? extends 
            ApplicationEvent>) eventType.resolve();
			return (eventClass != null && ((SmartApplicationListener) 
            this.delegate).supportsEventType(eventClass));
		}
		else {
			return (this.declaredEventType == null || 
            // 判断是不是事件的超类或者接口
            this.declaredEventType.isAssignableFrom(eventType));
		}
	}


	@Override
	public boolean supportsSourceType(@Nullable Class<?> sourceType) {
		return !(this.delegate instanceof SmartApplicationListener) ||
				((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);
	}

 

至此我们终于明白了,为什么spring把所有的listener放到一个广播里面,还能根据不同的事件区分。主要就是根据listener实现ApplicationListener的泛型类型和发送事件的类型相匹配,从而实行区分的。其实上面还有一个根据beanType查找时supportsEvent(listenerType, eventType)方法判断listener,原理和上面一样,就不分析了。

 

总结

本篇主要是根据springBoot的启动流程来分析SpringApplicationRunListeners的starting方法,这里面主要用到了几个listener的监听事件。从而引申出spring对于listener的使用。现在我们了解了spring的listener主要是用到了观察者模式,并且spring抽象出来一个广播的概念,由广播给我们派发事件,然后由符合要求的listener处理事件。对于如何是符合要求的listener呢,主要是依赖listener实现ApplicationListener的泛型类型和发送事件的类型相匹配,从而实行区分的。

对于SpringApplicationRunListeners的starting方法里面用到的几个事件处理呢,因为并不是很重要的处理,所以暂时没有细看。后面会介绍一些比较重要的事件处理,以及我们会用到的一些事件处理,方式都差不多,后面再做详细介绍吧。如果我再看SpringApplicationRunListeners的starting中有比较特殊重要的事件处理,再来补上。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值