• Springboot之事件管家SpringApplicationRunListeners事件管理机制源码分析


    Springboot的SpringApplication事件监听是独立于spring容器事件管理的另一套机制,分为:
    starting、environmentPrepared、contextPrepared、contextLoaded、started、running、failed等应用阶段的监听

    springboot启动的核心方法:

    public ConfigurableApplicationContext run(String... args) {
    		StopWatch stopWatch = new StopWatch();
    		stopWatch.start();
    		ConfigurableApplicationContext context = null;
    		configureHeadlessProperty();
    		// @A
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		listeners.starting();
    		try {
    			...省略...
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, listeners);
    			throw new IllegalStateException(ex);
    		}
    		try {
    			listeners.running(context);
    		}
    		catch (Throwable ex) {
    			handleRunFailure(context, ex, null);
    			throw new IllegalStateException(ex);
    		}
    		return context;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    @A:初步看来,spring-boot使用了 SpringApplicationRunListeners 这个类来抽象了spring应用运行时的一些event;SpringApplicationRunListeners 实则是对SpringApplicationRunListener子类集合的封装

    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();
    		// @A
    		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    		// @B
    		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    		this.mainApplicationClass = deduceMainApplicationClass();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    @A、@B:在这里我先讲SpringApplication的构造方法,是因为在构造方法里做了很多事情,跟本文有关的就是框架会在构造方法里从配置文件spring.factories里拿到key为org.springframework.context.ApplicationListener 和 key为org.springframework.context.ApplicationContextInitializer的类,实例化好后缓存起来

    这一点很重要,否则后面看代码会很绕;getSpringFactoriesInstances方法源码如下

    	private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
    		ClassLoader classLoader = getClassLoader();
    		// Use names and ensure unique to protect against duplicates
    		
    		// @A
    		Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
           	List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    		AnnotationAwareOrderComparator.sort(instances);
    		return instances;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    @A:解析配置文件并实例化,返回对象

    SpringApplicationRunListeners 初始化

    在调用spring-boot SpringApplication的run方法流程中,有一行代码:SpringApplicationRunListeners listeners = getRunListeners(args);
    在这里插入图片描述
    getRunListeners方法代码如下:

    	private SpringApplicationRunListeners getRunListeners(String[] args) {
    		Class[] types = new Class[] { SpringApplication.class, String[].class };
    		return new SpringApplicationRunListeners(logger,
    				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    	}
    
    	private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
    		ClassLoader classLoader = getClassLoader();
    		// Use names and ensure unique to protect against duplicates
    		
    		// @A
    		Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
            // @B
    		List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    		AnnotationAwareOrderComparator.sort(instances);
    		return instances;
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    @A:这个方法会到 spring.factories 文件里去拿 org.springframework.boot.SpringApplicationRunListener 为key 的value值
    @B:创建对应的实例集合,框架默认为SpringApplicationRunListener提供了一个子类 EventPublishingRunListener,所以instances的size是1

    EventPublishingRunListener

    我们来看看其构造方法

    	public EventPublishingRunListener(SpringApplication application, String[] args) {
    		this.application = application;
    		this.args = args;
    		this.initialMulticaster = new SimpleApplicationEventMulticaster();
    		// @A
    		for (ApplicationListener listener : application.getListeners()) {
    			this.initialMulticaster.addApplicationListener(listener);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @A:将application里的Listeners加载到自己类中,那么这些Listeners从哪里来的呢?
    这就跟上面的 SpringApplication 构造方法有关了,在构造方法里已经将这些listeners提前加载了!(我反正是debug了一大圈才发现!)
    这就完成了 EventPublishingRunListener 对象的初始化,后面springapplication的事件体系都由这个类来管控了!

    扩展点:spring cloud 就是扩展了 org.springframework.context.ApplicationListener 实现了双容器!下一篇再详细分析一下双容器。

    over~~

  • 相关阅读:
    【c++】缺省值、内联函数与常成员函数
    一种基于灰度映射以及直方图规定化的遥感图像对比度增强技术研究
    【Linux】写一个日志类
    openvino系列教程之人脸检测 mobilenetv2
    “当下的力量”9月读书笔记
    OpenCV-Python小应用(五):基于模板匹配的图像拼接
    web前端期末大作业 html+css学生心理 7页主题网页设计
    SpringBoot实现Excel导入导出
    需求评审,测试人员应该发挥怎样的价值?两分钟让你不再懵逼
    施耐德电气携中国信通院和中国联通共同发布白皮书,共探5G+PLC深度融合应用
  • 原文地址:https://blog.csdn.net/Aqu415/article/details/126197702