关闭

【深入SpringBoot 第三章】SpringApplicationRunListener及其周期

5655人阅读 评论(2) 收藏 举报
分类:

一 SpringApplicationRunListener 类

三种监听器的关系

SpringApplicationRunListeners类和SpringApplicationRunListener类是SpringBoot中新增的类。SpringApplication类 中使用它们来间接调用ApplicationListener

SpringApplicationRunListeners包含了多个SpringApplicationRunListener。

SpringApplicationRunListener介绍

SpringApplicationRunListener接口规定了SpringBoot的生命周期,在各个生命周期广播相应的事件,调用实际的ApplicationListener类。

接口定义如下:

public interface SpringApplicationRunListener {

     //刚执行run方法时
    void started();
     //环境建立好时候
    void environmentPrepared(ConfigurableEnvironment environment);
     //上下文建立好的时候
    void contextPrepared(ConfigurableApplicationContext context);
    //上下文载入配置时候
    void contextLoaded(ConfigurableApplicationContext context);
    //上下文刷新完成后,run方法执行完之前
    void finished(ConfigurableApplicationContext context, Throwable exception);

}

SpringApplication类实际使用的是SpringApplicationRunListeners类,它可以包含多个SpringApplicationRunListener实例,与SpringApplicationRunListener生命周期相同,调用每个周期的各个SpringApplicationRunListener。然后广播相应的事件到ApplicationListener

实现类 EventPublishingRunListener类

EventPublishingRunListener类 实现了SpringApplicationRunListener,它具有广播事件的功能。

构造函数
从下面代码可以看出,它使用了Spring广播器SimpleApplicationEventMulticaster

public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        //新建立广播器
        this.multicaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.multicaster.addApplicationListener(listener);
        }
    }

* 当上下文准备好时候,注册名为“applicationEventMulticaster”的bean*

@Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        registerApplicationEventMulticaster(context);
    }

    private void registerApplicationEventMulticaster(
            ConfigurableApplicationContext context) {
        context.getBeanFactory().registerSingleton(
                AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
                this.multicaster);
        if (this.multicaster instanceof BeanFactoryAware) {
            ((BeanFactoryAware) this.multicaster)
                    .setBeanFactory(context.getBeanFactory());
        }
    }

把SpringApplication对象中暂存的所有监听器交给相应的Context
在上下文载入后:

   @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        for (ApplicationListener<?> listener : this.application.getListeners()) {
            if (listener instanceof ApplicationContextAware) {
                ((ApplicationContextAware) listener).setApplicationContext(context);
            }
            context.addApplicationListener(listener);
        }
        publishEvent(new ApplicationPreparedEvent(this.application, this.args, context));
    }

拓展:SpringContext如何的到监听器???
当使用SpringApplication#createAndRefreshContext(..)中refresh(context)时,
在AbstractApplicationContext类 中,有如下方法:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if(beanFactory.containsLocalBean("applicationEventMulticaster")) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        } else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Unable to locate ApplicationEventMulticaster with name \'applicationEventMulticaster\': using default [" + this.applicationEventMulticaster + "]");
            }
        }

    }

可以看出,前面注册了名为“applicationEventMulticaster”的bean,所以SpringContext不会创建另外的广播器,而是使用我们在EventPublishingRunListener建立的。

EventPublishingRunListener类生命周期对应的事件

从它的源码中可以看出
started()—>ApplicationStartedEvent事件类

environmentPrepared(Environment e)—>ApplicationEnvironmentPreparedEvent事件类

contextPrepared(ApplicationContext c)–>在context中注册广播器bean

contextLoaded(ApplicationContext c)–>ApplicationPreparedEvent事件

finished(ApplicationContext context, Throwable t) –>ApplicationFailedEvent()和ApplicationReadyEvent()事件

二 在Boot中自定义SpringApplicationRunListener和ApplicationListener

自定义SpringApplicationRunListener(不推荐)

SpringApplication类没有直接添加SpringApplicationRunListener的方法。查看源码可知, 可以在spring.factory中定义org.springframework.boot.SpringApplicationRunListener=xxx,就会被初始化(与在第一章中初始化函数中相同)。
自己实现的类必须含有以下构造函数,才能被Boot调用

 public MyRunListener(SpringApplication application, String[] args) {
 }

META-INF/spring.factory

org.springframework.boot.SpringApplicationRunListener=\
com.jazz.other.MyRunListener

自定义ApplicationListener

* 方法一:代码中添加*
使用SpringApplication#setListeners方法添加监听器SpringApplication#setListeners(..[])或者addListeners(..)

使用泛型构造专门接收ApplicationStartedEvent事件的监听器

public class MyStartListner implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("我的程序启动啦!!!");
    }
}

主程序

 public static void main(String[] args) {
        SpringApplication application = new SpringApplication(App.class);
        application.addListeners(new MyStartListner());
        application.run(args);
   }

屏幕输出:

我的程序启动啦!!!
. _ _ _
/\ / _ ()_ _ _ _ \ \ \ \
( ( )___ | ‘_ | ‘| | ‘ \/ _` | \ \ \ \
\/ _)| |)| | | | | || (| | ) ) ) )
’ |_| .|| ||| |_, | / / / /
=========||==============|__/=///_/
:: Spring Boot :: (v1.3.5.RELEASE)

2016-05-26 21:25:23.998 INFO 5008 — [ main] App : Starting App > on Jiazhi-PC with PID 5008 (E:\IdeaProjects\test\target\classes started by Jiazhi in > > E:\IdeaProjects\test)
2016-05-26 21:25:24.000 INFO 5008 — [ …….//省略

方法二:文件中添加
根目录下建立 META-INF/spring.factory,添加自定义的监听器到org.springframework.context.ApplicationListener键

0
0
查看评论

Spring Boot【原理分析】(1)——SpringApplication

SpringApplication作为Spring Boot的启动类。 一、入口方法run public static ConfigurableApplicationContext run(Object source, String… args) { return ru...
  • wwmfeng
  • wwmfeng
  • 2016-12-05 11:04
  • 2071

spring boot实战(第三篇)事件监听源码分析

spring boot实战(第三篇)事件监听源码分析前言解读源码,知其然知其所以然···监听源码分析首先来看下上一篇中执行的main方法package com.u51.lkl.springboot;import org.springframework.boot.Spri...
  • liaokailin
  • liaokailin
  • 2015-09-03 14:42
  • 13665

[Spring Boot] 2. Spring Boot 启动过程定制化

在上一篇文章中,从源码角度介绍了Spring Boot的启动过程。启动的代码虽然只有短短的一行,但是背后所做的工作还真不少,其中有一些可以定制化的部分,主要分为以下几个方面: 初始化器(Initializer) 监听器(Listener) 容器刷新后置Runners(ApplicationRunne...
  • dm_vincent
  • dm_vincent
  • 2017-08-13 22:45
  • 867

Application.Run() 和 System.Windows.Forms.Form.Show() 方法的区别

其实这个题目和内容有点不符,但是目前也就这些理解,为了不至于由于时间的关系而忘记,先写下一些不成熟的文字。以后有了新的,更加深刻的理解再将其完善。各位如果有什么简介和意见我也是非常欢迎的。很少写WinForm的程序,这回需要自己写一个邮件发送程序,为了减少直接操作配置文件而产生错误的可能性,所以决定...
  • vividboy
  • vividboy
  • 2007-01-15 21:39
  • 14427

Spring Boot 生命周期

application.properties中,添加: context.listener.classes=com.example.listener.ApplicationEventListener 实现ApplicationListener接口: public class Applicat...
  • lc0817
  • lc0817
  • 2016-09-29 17:38
  • 1833

Spring源码学习--Bean的生命周期

Spring作为当前Java最流行、最强大的轻量级框架,受到了程序员的热烈欢迎。准确的了解Spring Bean的生命周期是非常必要的。我们通常使用ApplicationContext作为Spring容器。这里,我们讲的也是 ApplicationContext中Bean的生命周期。而实际上Bean...
  • qq924862077
  • qq924862077
  • 2017-07-13 10:19
  • 864

Spring Boot深入详解

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Boot致力于在蓬勃发展的快速应用开发领域(rapid application dev...
  • m0_37327416
  • m0_37327416
  • 2017-09-28 18:19
  • 234

Spring 之 生命周期机制混合使用

对于同一个bean,有多种生命周期机制,其有不同的初始化方法,如下所示:   1        使用@PostConstruct注解的方法 2    实现了Initializ...
  • luccs624061082
  • luccs624061082
  • 2014-09-15 09:05
  • 6386

Spring Boot的SpringApplication类详解

相信使用过Spring Boot的开发人员,都对Spring Boot的核心模块中提供的SpringApplication类不陌生。SpringApplication类的run()方法往往在Spring应用的入口类中被调用,以启动Spring应用。 1.Spring应用的入口类与SpringApp...
  • taiyangdao
  • taiyangdao
  • 2017-08-13 21:18
  • 1449

spring boot(18)-servlet、filter、listener

servlet、filter、listener的用法就不讲了,只讲如何在spring boot中配置它们。有两种方式,一种是从servlet3开始提供的注解方式,另一种是spring的注入方式 servlet注解方式 servlet3.0以前,servlet、filter、listener需要在...
  • wangb_java
  • wangb_java
  • 2017-09-09 10:25
  • 1297
    个人资料
    • 访问:222047次
    • 积分:3393
    • 等级:
    • 排名:第11743名
    • 原创:98篇
    • 转载:20篇
    • 译文:0篇
    • 评论:67条
    个人简介
    联系方式:
    【Email】chenjazz@foxmail.com
    博客专栏
    最新评论