栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Boot 2.x源码系列【4】启动流程深入解析之启动监听器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Boot 2.x源码系列【4】启动流程深入解析之启动监听器

有道无术,术尚可求,有术无道,止于术。

本系列Spring Boot版本2.7.0

文章目录
    • 前言
    • 核心类及接口
      • ConfigurableApplicationContext
      • SpringApplicationRunListener
      • ApplicationListener
      • ApplicationStartup
    • 1. 设置Headless
    • 2. 获取监听器
    • 3. 开启步骤
    • 4. 广播事件
    • 5. 调用Spring 监听器
    • 总结

前言

紧接上文,接下来分析下面这几步:

		ConfigurableApplicationContext context = null;
		// 配置Headless
		configureHeadlessProperty();
		// 获取监听器集合
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 调用监听器启动方法
		listeners.starting(bootstrapContext, this.mainApplicationClass);
核心类及接口 ConfigurableApplicationContext

ConfigurableApplicationContext 是Spring 提供的接口,翻译过来就是可配置应用上下文的意思,可以看到它继承了很多接口,上一级继承的接口有:

  • ApplicationContext:引用上下文接口,也就是IOC容器接口
  • Lifecycle:容器生命周期接口
  • Closeable:JDK释放资源接口

该接口的源码如下:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
	// 配置文件路径分隔符,主要用来分割各个配置文件路径
    String CONFIG_LOCATION_DELIMITERS = ",; tn";
    // 转换服务的bean 名称,通过这个服务,我们则可以实现类型转换操作
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
    // 工厂中LoadTimeWeaver bean的名称
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
    // 环境{@link-Environment}bean的名称。
    String ENVIRONMENT_BEAN_NAME = "environment";
    // 系统属性的bean 名称
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
    // 系统环境的bean 名称
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
    //  {@link ApplicationStartup} 的bean 名称
    String APPLICATION_STARTUP_BEAN_NAME = "applicationStartup";
    // 关闭钩子函数线程名称
    String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";
	// 设置应用容器的唯一id
    void setId(String id);
	// 设置父级容器(上下文)
    void setParent(@Nullable ApplicationContext parent);
	// 设置当前容器环境
    void setEnvironment(ConfigurableEnvironment environment);
	// 返回此应用程序上下文的环境,允许进一步自定义
    ConfigurableEnvironment getEnvironment();
	// 设置ApplicationStartup
    void setApplicationStartup(ApplicationStartup applicationStartup);
	// 获取 ApplicationStartup
    ApplicationStartup getApplicationStartup();
	// 添加BeanFactoryPostProcessor
    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
	// 添加容器监听器,主要是指继承了ApplicationListener的监听器
    void addApplicationListener(ApplicationListener listener);
	// 设置类加载器
    void setClassLoader(ClassLoader classLoader);
	// 注册协议解析器。协议解析器的作用就是根据指定的地址和资源加载期,解析资源并将资源返回
    void addProtocolResolver(ProtocolResolver resolver);
	// 核心方法:加载|刷新 整个容器
    void refresh() throws BeansException, IllegalStateException;
	// 注册关闭钩子
    void registerShutdownHook();
	// 关闭容器
    void close();
	// 获取容器是否活跃
    boolean isActive();
	// 获取bean factory
    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

由上可知,ConfigurableApplicationContext 就是Spring Boot中的应用上下文对象,也就是Spring 容器。

SpringApplicationRunListener

SpringApplicationRunListener是Spring Boot提供的接口,从字面上看,它是一个Spring 应用启动监听器。

学过Spring 的应该知道,有个事件监听器机制,是在观察者模式基础上的进一步抽象和改进,定义了一个ApplicationListener接口作为事件监听器的抽象,当监听的事件在容器中被发布,onApplicationEvent方法将被调用。

public interface ApplicationListener extends EventListener {

   
   void onApplicationEvent(E event);
}

SpringApplicationRunListener就是用来在整个启动流程中接收不同执行点事件通知的监听者,可以在接口定义中看到,一旦启动阶段发布了事件,该监听器就会观察到事件被做出相应操作。

public interface SpringApplicationRunListener {
	// 首次启动run方法时立即调用。可用于非常早期初始化。
    default void starting(ConfigurableBootstrapContext bootstrapContext) {
    }
	// 环境准备就绪,但在{@link ApplicationContext}创建之前。
    default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
    }
	// 在创建和准备{@link ApplicationContext}后,但在加载源之前调用。
    default void contextPrepared(ConfigurableApplicationContext context) {
    }
	// 在加载应用程序上下文之后但在加载之前调用已刷新。
    default void contextLoaded(ConfigurableApplicationContext context) {
    }
	// 上下文已刷新,应用程序已启动,但{@link CommandLineRunner CommandLineRunner}和{@link ApplicationRunner}未调用。
    default void started(ConfigurableApplicationContext context, Duration timeTaken) {
        this.started(context);
    }
	
    
    @Deprecated
    default void started(ConfigurableApplicationContext context) {
    }
	// 当应用程序上下文已刷新且所有{@link CommandLineRunner CommandLineRunner}和{@link ApplicationRunner ApplicationRunners}已调用。
    default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        this.running(context);
    }
	
    
    @Deprecated
    default void running(ConfigurableApplicationContext context) {
    }
	// 运行应用程序时发生故障时调用。
    default void failed(ConfigurableApplicationContext context, Throwable exception) {
    }
}
ApplicationListener

ApplicationListener是Spring 中的监听器接口,可以看到在spring.factories中定义了7种监听器。

SpringApplication对象在创建的时候,会去获取这些监听器。

    public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    // ..........
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    }

ApplicationStartup

ApplicationStartup 字面上看是应用启动的意思,它的作用是标记应用程序启动期间的步骤,并收集有关执行上下文或其处理时间的数据。

该接口只有一个start方法,传入一个步骤名称参数,描述当前操作或阶段,然后创建一个步骤对象并标记它的开始,然后返回当前StartupStep (启动步骤)对象。

public interface ApplicationStartup {
    ApplicationStartup DEFAULT = new DefaultApplicationStartup();

    StartupStep start(String name);
}

可理解为当前接口的功能就是记录每一个启动步骤的相关检测数据。

1. 设置Headless
private void configureHeadlessProperty() {
		// java.awt.headless
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

configureHeadlessProperty方法很简单,就是设置了一个java.awt.headless系统参数,默认为true,表示开启Headless(中文无头、无外设的意思)模式。

程序在运行时,可能需要使用外设(显示屏、键盘、鼠标)或者获取外设的信息,但一般部署的服务器是没有这些设备的,这个时候就可以开启Headless模式,告诉程序当前环境没有外设,需要依靠系统的计算能力模拟出这些外设特性。

2. 获取监听器

getRunListeners方法获取监听器,返回一个SpringApplicationRunListeners 对象。

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		// 1. 创建一个数组,存放SpringApplication.class、String[].class
		Class[] types = new Class[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				// SPI机制,从spring.factories 中获取SpringApplicationRunListener实例
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
				this.applicationStartup);
	}

这里可以看到又是使用SPI 机制从META-INF/spring.factories中获取SpringApplicationRunListener类型的实例,可以在源码spring-boot模块中看到只配置了一个该类型的监听器EventPublishingRunListener。

最后将获取到监听器,放入到SpringApplicationRunListeners 对象的成员属性中:

3. 开启步骤

接着进入到SpringApplicationRunListeners 对象的starting方法,可以看到在该方法中,直接转到了doWithListeners方法,参数为一个字符串,两个为Consumer函数式接口的匿名内部类。

    void starting(ConfigurableBootstrapContext bootstrapContext, Class mainApplicationClass) {
        this.doWithListeners("spring.boot.application.starting", (listener) -> {
            listener.starting(bootstrapContext);
        }, (step) -> {
            if (mainApplicationClass != null) {
                step.tag("mainApplicationClass", mainApplicationClass.getName());
            }

        });
    }

接着进入到其doWithListeners方法,可以看到在该方法中,会调用所有监听器的starting 方法,并记录一个名称为spring.boot.application.starting 的步骤,所有监听器的starting 方法执行完成后,该步骤结束。

    private void doWithListeners(String stepName, Consumer listenerAction, Consumer stepAction) {
    	// 1. 步骤名为spring.boot.application.starting 
        StartupStep step = this.applicationStartup.start(stepName);
        // 2. 循环所有监听器,调用其starting 方法
        this.listeners.forEach(listenerAction);
        // 3. 记录步骤标记 
        if (stepAction != null) {
            stepAction.accept(step);
        }
		// 4. 步骤结束。
        step.end();
    }
4. 广播事件

因为默认只有一个EventPublishingRunListener监听器,所以这里会进入到该监听器中,会调用SimpleApplicationEventMulticaster对象的multicastEvent方法,参数为ApplicationStartingEvent,该方法从名字上看是进行事件广播,它的作用是会将启动事件,发布给所有的监听器。

    public void starting(ConfigurableBootstrapContext bootstrapContext) {
    	// 广播事件
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
    }

ApplicationStartingEvent对象比较简单,就是一个应用启动事件对象,封装了引导上下文和SpringApplication对象。

接着进入到SimpleApplicationEventMulticaster对象的multicastEvent方法:

    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    	// 1. 解析事件的类型=》ApplicationStartingEvent
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        // 2. 获取线程池,初次为NULL 
        Executor executor = this.getTaskExecutor();        
        Iterator var5 = this.getApplicationListeners(event, type).iterator();
		// 3. 循环获取到的监听器,并调用监听器的监听方法
        while(var5.hasNext()) {
            ApplicationListener listener = (ApplicationListener)var5.next();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
            	// 线程池不存在,所以调用这一步
                this.invokeListener(listener, event);
            }
        }

    }

getApplicationListeners方法会获取所有支持当前事件的的监听器,不匹配的提前被排除在外。

	protected Collection> getApplicationListeners(
			ApplicationEvent event, ResolvableType eventType) {
		// 1. 当前事件的来源,SpringApplication
		Object source = event.getSource();
		Class sourceType = (source != null ? source.getClass() : null);
		// 2. 创建缓存的 KEY 
		ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
		// Potential new retriever to populate
		CachedListenerRetriever newRetriever = null;
		
		// 3. 缓存中查询是有
		CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
		if (existingRetriever == null) {
			// Caching a new ListenerRetriever if possible
			if (this.beanClassLoader == null ||
					(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
							(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
				newRetriever = new CachedListenerRetriever();
				existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
				if (existingRetriever != null) {
					newRetriever = null;  // no need to populate it in retrieveApplicationListeners
				}
			}
		}
		if (existingRetriever != null) {
			Collection> result = existingRetriever.getApplicationListeners();
			if (result != null) {
				return result;
			}
			// If result is null, the existing retriever is not fully populated yet by another thread.
			// Proceed like caching wasn't possible for this current local attempt.
		}
		// 4. 缓存中没有,所以进入该方法
		return retrieveApplicationListeners(eventType, sourceType, newRetriever);
	}

因为缓存中没有,所以进入retrieveApplicationListeners方法,查询监听器,是之前SpringApplication对象创建的时候从spring.factries中加载的。

    private Collection> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {
    	// 1. 创建一个集合对象,用于存放ApplicationListener(spring 提供的监听器) 
        List> allListeners = new ArrayList();
        Set> filteredListeners = retriever != null ? new LinkedHashSet() : null;
        Set filteredListenerBeans = retriever != null ? new LinkedHashSet() : null;
        LinkedHashSet listeners; // 所有的ApplicationListener
        LinkedHashSet listenerBeans;
        // 从默认的持有着中获取监听器,
        synchronized(this.defaultRetriever) {
            listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
        }

        Iterator var9 = listeners.iterator();
		// 2. 循环所有的ApplicationListener,校验这些监听器是否支持ApplicationStartingEvent 事件
		// LoggingApplicationListener,BackgroundPreinitializer,DelegatingApplicationListener
        while(var9.hasNext()) {
            ApplicationListener listener = (ApplicationListener)var9.next();
            if (this.supportsEvent(listener, eventType, sourceType)) {
                if (retriever != null) {
                    filteredListeners.add(listener);
                }

                allListeners.add(listener);
            }
        }
		// 3. 没有查到这些监听器的Bean 对象,没有这里为空,直接跳过
		// 该方法根据注册的Bean ,去查询是否支持事件,并添加到监听器集合中
        if (!listenerBeans.isEmpty()) {
            ConfigurableBeanFactory beanFactory = this.getBeanFactory();
            Iterator var16 = listenerBeans.iterator();

            while(var16.hasNext()) {
                String listenerBeanName = (String)var16.next();

                try {
                    if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {
                        ApplicationListener listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
                            if (retriever != null) {
                                if (beanFactory.isSingleton(listenerBeanName)) {
                                    filteredListeners.add(listener);
                                } else {
                                    filteredListenerBeans.add(listenerBeanName);
                                }
                            }

                            allListeners.add(listener);
                        }
                    } else {
                        Object listener = beanFactory.getSingleton(listenerBeanName);
                        if (retriever != null) {
                            filteredListeners.remove(listener);
                        }

                        allListeners.remove(listener);
                    }
                } catch (NoSuchBeanDefinitionException var13) {
                }
            }
        }

        AnnotationAwareOrderComparator.sort(allListeners);
        // 4. 将这些监听器和Bean放入到缓存中
        if (retriever != null) {
            if (filteredListenerBeans.isEmpty()) {
                retriever.applicationListeners = new LinkedHashSet(allListeners);
                retriever.applicationListenerBeans = filteredListenerBeans;
            } else {
                retriever.applicationListeners = filteredListeners;
                retriever.applicationListenerBeans = filteredListenerBeans;
            }
        }

        return allListeners;
    }
5. 调用Spring 监听器

接着将符合条件的监听器返回,可以看到,缓存中存放了三个监听器:

接着循环执行执行监听器的doInvokeListener方法,进入调用三个监听器的onApplicationEvent方法。

    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        } catch (ClassCastException var6) {
            // 省略异常捕获代码 
        }
    }

首先循环的是LoggingApplicationListener(日志监听器),它的作用很重要,会完成日志系统的加载和初始化,默认使用的是Logback日志组件。

    private void onApplicationStartingEvent(ApplicationStartingEvent event) {
    	// 使用ClassLoader 加载日志系统,默认是LogbackLoggingSystem 
        this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
        // 日志系统初始化
        this.loggingSystem.beforeInitialize();
    }

接着进入到BackgroundPreinitializer(后台预先初始化监听器),该监听器的作用是将一些比较耗时的组件开启后台线程预先初始化,这里是刚开始启动阶段,所有这里也有没进行操作。

    public void onApplicationEvent(SpringApplicationEvent event) {
    	// 1. 查看spring.backgroundpreinitializer.ignore 配置,是否开启预先初始化
        if (ENABLED) {
        	// 2. 是否环境准备事件,是的话,会开启异步线程,初始化Jackson、Charset、ConversionService、Validation、MessageConverter等
            if (event instanceof ApplicationEnvironmentPreparedEvent && preinitializationStarted.compareAndSet(false, true)) {
                this.performPreinitialization();
            }
            if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) && preinitializationStarted.get()) {
                try {
                    preinitializationComplete.await();
                } catch (InterruptedException var3) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

接着DelegatingApplicationListener(委托应用监听器),监听到事件后转发给环境变量context.listener.classes指定的那些事件监听器,这里也是跳过,没有任何操作。

    public void onApplicationEvent(ApplicationEvent event) {
    	// 1. 判断是否是环境准备事件,这里是刚启动,所以跳过
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            List> delegates = this.getListeners(((ApplicationEnvironmentPreparedEvent)event).getEnvironment());
            if (delegates.isEmpty()) {
                return;
            }

            this.multicaster = new SimpleApplicationEventMulticaster();
            Iterator var3 = delegates.iterator();

            while(var3.hasNext()) {
                ApplicationListener listener = (ApplicationListener)var3.next();
                this.multicaster.addApplicationListener(listener);
            }
        }

        if (this.multicaster != null) {
            this.multicaster.multicastEvent(event);
        }

    }

最后,监听器执行完毕,启动开始阶段标记为结束。

总结
  1. 获取Spring Boot 自己的监听器SpringApplicationRunListener,调用starting开始启动;
  2. 创建步骤spring.boot.application.starting ,调用EventPublishingRunListener进行事件广播;
  3. 获取Spring 监听器ApplicationListener并过滤,最后有三个支持当前事件的监听器;
  4. 循环调用监听器的onApplicationEvent方法,最终只有LoggingApplicationListener(日志监听器)实际执行了处理(初始化日志系统);
  5. 执行完成,开始启动步骤标记为结束。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995553.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号