• SpringBoot事件机制


    SpringBoot事件机制

    启动入口

    SpringApplication.run(H2Application.class, args);方法

    public ConfigurableApplicationContext run(String... args) {
    		StopWatch stopWatch = new StopWatch();
    		stopWatch.start();
    		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    		ConfigurableApplicationContext context = null;
    		configureHeadlessProperty();
    		SpringApplicationRunListeners listeners = getRunListeners(args);
        	//1.发送ApplicationStartingEvent事件,回调starting
    		listeners.starting(bootstrapContext, this.mainApplicationClass);
    		try {
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                //2.发送ApplicationEnvironmentPreparedEvent事件,回调environmentPrepared,
                //listeners.environmentPrepared(bootstrapContext, environment);
    			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
    			configureIgnoreBeanInfo(environment);
    			Banner printedBanner = printBanner(environment);
    			context = createApplicationContext();
    			context.setApplicationStartup(this.applicationStartup);
                //3.listeners.contextPrepared(context);
                //4.listeners.contextLoaded(context);
    			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    			refreshContext(context);
    			afterRefresh(context, applicationArguments);
    			stopWatch.stop();
    			if (this.logStartupInfo) {
    				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    			}
                //5.ApplicationStartedEvent事件 listeners.started(context);
    			listeners.started(context);
    			callRunners(context, applicationArguments);
    		}
    		catch (Throwable ex) {
                //ApplicationFailedEvent
    			handleRunFailure(context, ex, listeners);
    			throw new IllegalStateException(ex);
    		}
    
    		try {
                //6.ApplicationReadyEvent事件 listeners.running(context);
    			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
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    事件整理

    事件含义:

    事件名称回调方法含义主要动作
    ApplicationStartingEventstartingSpirng应用开始了
    ApplicationEnvironmentPreparedEventenvironmentPrepared应用环境变量配置完成
    ApplicationContextInitializedEventcontextPrepared准备ApplicationContext
    ApplicationPreparedEventcontextLoaded完成ApplicationContext
    ApplicationStartedEventstartedSpring应用启动结束;执行ApplicationRunner和CommandLineRunner
    ApplicationReadyEventrunningSpring应用正式启动完成
    ApplicationFailedEventfailedSpring应用启动失败

    自定义事件

    复用SpringBoot内置事件机制,自定义,参考:context.publishEvent(new ExitCodeEvent(context, exitCode));

    这里顺便梳理一下SprinBoot的启动流程,我们知道SpringBoot的启动入口是SpringApplication#run,涉及SpringApplication的构造函数和run方法。

    • SpringApplication的构造函数

      1. 将启动类放入primarySource;this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

      2. 推算当前web应用类型;this.webApplicationType = WebApplicationType.deduceFromClasspath();

      3. 读取ApplicationContextInitializer初始化器,ApplicationListener配置并赋值

        getSpringFactoriesInstances(ApplicationContextInitializer.class)//this.initializers
        getSpringFactoriesInstances(ApplicationListener.class))//this.listeners
        
        • 1
        • 2
      4. 将main方法所有的类放入mainApplicationClass; this.mainApplicationClass = deduceMainApplicationClass();

    • run方法

      1. 记录启动时间,开启hendless,读取SpringApplicationRunListener配置;发布ApplicationStartingEvent

      2. 封装命令行参数applicationArgument,读取环境配置prepareEnvironment,在其中发布ApplicationEnvironmentPreparedEvent

      3. 设置忽略的bean,configureIgnoreBeanInfo,从系统变量中获取"spring.beaninfo.ignore"并设置

      4. 打印banner

      5. 创建applicationContext

      6. 准备applicationContext,在其中发布ApplicationContextInitializedEvent

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a7d6JRU7-1662108419324)(E:\pic\image-20220902154055159.png)]

      7. 刷新applicationContext

      8. 刷新后applicationContext,留待扩展,完成后发布ApplicationStartedEvent,执行完Runners后,发布ApplicationReadyEvent

    定阅事件

    @Component
    public class UserRegisterSendSMSListener implements ApplicationListener<UserRegisterEvent> {
     
        private static final Logger LOGGER = LoggerFactory.getLogger(UserRegisterSendSMSListener.class);
     
        @Override
        public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
            // 发送短信
            LOGGER.info("新注册用户 {} 短信发送成功", userRegisterEvent.getUser().getUserName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    发布事件

    @RestController
    @RequestMapping("user")
    public class UserController {
     
        @Autowired
        private ApplicationEventPublisher applicationEventPublisher;
     
        @PostMapping
        public String register(@RequestBody UserModel model) {
            // 验证
            // 注册
            // 事件
            UserRegisterEvent userRegisterEvent = new UserRegisterEvent(this, model);
            applicationEventPublisher.publishEvent(userRegisterEvent);
            return Boolean.TRUE.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    自定义监听

    package com.dxz.controller;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.SpringApplicationRunListener;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.core.env.ConfigurableEnvironment;
    
    public class SampleSpringApplicationRunListener implements SpringApplicationRunListener {
        private final SpringApplication application;
        private final String[] args;
    	
        //任何一个SpringApplicationRunListener实现类的构造方法都需要有两个构造参数,一个参数的类型就是我们的org.springframework.boot.SpringApplication,另外一个参数就是args参数列表的String[]
        public SampleSpringApplicationRunListener(SpringApplication sa, String[] args) {
            this.application = sa;
            this.args = args;
        }
    
        @Override
        public void starting() {
            System.out.println("自定义starting");
        }
    
        @Override
        public void environmentPrepared(ConfigurableEnvironment environment) {
            System.out.println("自定义environmentPrepared");
        }
    
        @Override
        public void contextPrepared(ConfigurableApplicationContext context) {
            System.out.println("自定义contextPrepared");
        }
    
        @Override
        public void contextLoaded(ConfigurableApplicationContext context) {
            System.out.println("自定义contextLoaded");
        }
    
        @Override
        public void finished(ConfigurableApplicationContext context, Throwable exception) {
            System.out.println("自定义finished");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    org.springframework.boot.SpringApplicationRunListener=\
        com.dxz.SampleSpringApplicationRunListener
    
    • 1
    • 2
  • 相关阅读:
    python程序将pdf转word
    MyBioSource 重组人白细胞介素-24解决方案
    硬件设计专题-DCDC电路起源
    Axure RP Pro 8 mac/win中文版:打造无限可能的原型设计工具
    2.1.4 运算放大器的等效模型、理想运算放大器的特性
    星戈瑞DSPE-SS-PEG-CY7近红外花菁染料
    【uvm】Wait for Interface Signals in UVM
    基于DSP的专业缩略词
    JavaScript函数this指向
    【侯捷C++-----STL与泛型编程】
  • 原文地址:https://blog.csdn.net/sunquan291/article/details/126639142