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

3141人阅读 评论(0) 收藏 举报
分类:

一 SpringApplicationRunListener 类

SpringApplicationRunListeners/ SpringApplicationRunListener和ApplicationListener关系

和SpringApplicationRunListener是Boot中新增的类。SpringApplication类中使用它们来间接调用ApplicationListener。
SpringApplicationRunListeners包含多个SpringApplicationRunListener。

SpringApplicationRunListener介绍

SpringApplicationRunListener接口规定了Boot的生命周期,在各个生命周期广播相应的事件,调用实际的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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:146709次
    • 积分:2546
    • 等级:
    • 排名:第14431名
    • 原创:98篇
    • 转载:20篇
    • 译文:0篇
    • 评论:58条
    个人简介
    联系方式:
    【Email】chenjazz@foxmail.com
    博客专栏
    最新评论