Spring ApplicationListener学习

一. 观察者模式

观察者模式又称发布-订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态变化时,会通知所有的观察者对象,让他们自动更新自己;

观察者模式结构图如下:

在这里插入图片描述

观察者模式中如下角色:

  • Subject:被观察者(抽象主体),被观察者把所有观察者对象保存在一个集合里,每个主体都可以有任意数量的观察者,抽象主体提供一个接口,可以增加和删除观察者对象;
  • Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主体更新通知时更新自己;

二. Spring ApplicationListener的应用

通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现 ApplicationContext 的事件处理,如果容器中有一个 ApplicationListener bean,当 ApplicationContext 发布 ApplicationEvent 时,ApplicationListener bean 将自动被触发;

1. ApplicationEventPublisher

封装事件发布功能的接口,它有两个接口;

public interface ApplicationEventPublisher {

    default void publishEvent(ApplicationEvent event) {
        publishEvent((Object) event);
    }

    void publishEvent(Object event);

}

我们的 ApplicationContext 会实现这个接口,看如下类继承图;

在这里插入图片描述

2. ApplicationEvent

ApplicationEvent 是 Spring 应用程序中的事件,在 Spring 容器中发布的事件应该都继承 ApplicationEvent;

//------------------------ ApplicationEvent --------------------------
public abstract class ApplicationEvent extends EventObject {

   /** System time when the event happened. */
   private final long timestamp;

    
   public ApplicationEvent(Object source) {
      super(source);
      this.timestamp = System.currentTimeMillis();
   }
    
}



// ------------------------- EventObject ----------------------------
public class EventObject implements java.io.Serializable {

    /**
     * 事件最初触发的对象
     */
    protected transient Object  source;

    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }
}

3. ApplicationListener

ApplicationListener 是监听器,它有一个抽象方法 onApplicationEvent();

public interface ApplicationListener<E extends ApplicationEvent>
    extends EventListener {

    void onApplicationEvent(E event);

}

我们往容器中注册的监听器都应该实现 ApplicationListener,并实现它的抽象方法 onApplicationEvent(),需要注意实现泛型接口的方式;示例如下:

@Component
public class TestApplicationListener01 implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println(contextRefreshedEvent);
        System.out.println("TestApplicationListener01............................");
    }
}

由上面的流程,只需要在容器中注册实现了 ApplicationListener 的 bean,当 ApplicationContext 发布事件的时候,就会被监听器自动监听;

4. Spring的内置事件

Spring 有一些内置的事件,当完成某种操作时会发出某些事件动作。比如监听 ContextRefreshedEvent 事件,当所有的 bean 都初始化完成并被成功装载后会触发该事件,实现 ApplicationListener< ContextRefreshedEvent > 接口可以收到监听动作,然后可以写自己的逻辑。

  1. ContextRefreshedEvent:ApplicationContext 容器初始化或刷新触发该事件。此处说的初始化,是指所有的 bean 被成功加载,后处理的 bean 被检测激活,所有的 singleton bean 被预初始化,ApplicationContext 容器已就绪可用。
  2. ContextStartdEvent:当使用 ApplicationContext 的子接口 ConfigurableApplicationContext 接口的start() 启动 ApplicationContext 容器时触发该事件。容器管理生命周期的 bean 实例将获得一个指定的启动信号,这在经常需要停止后重新启动的场合比较常见。
  3. ContextClossedEvent:当使用 ConfigurableApplicationContext 接口的 close() 关闭ApplicationContext容器时触发该事件。
  4. ContextStoppedEvent:当使用 ConfigurableApplicationContext 接口的 stop() 使ApplicationContext 容器停止时触发该事件 。此处的停止意味着,容器管理生命周期的 bean 实例将获得一个指定的停止信号。被停止的 Spring 容器可以再次通过调用 start() 重新启动。
  5. RequestHandledEvent:Web 相关的事件,只能应用于使用 DispatcherServlet 的 Web 应用中。在使用 Spring 作为前端的 MVC 控制器时,当 Spring 处理用户请求结束后,系统会自动触发该事件。

比如要监听 ContextRefreshedEvent 时可以实现 ApplicationListener 接口;

@Component
public class TestApplicationListener01 implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println(contextRefreshedEvent);
        System.out.println("TestApplicationListener01............................");
    }
}

5. 自定义事件

我们自定义事件和自定义监听器,如下:

EmailEvent:

@Getter
@Setter
public class EmailEvent extends ApplicationEvent {

    private String address;

    private String text;

    public EmailEvent(Object source) {
        super(source);
    }

    public EmailEvent(Object source, String address, String text) {
        super(source);
        this.address = address;
        this.text = text;
    }
}

TestEmailListener:

@Component
public class TestEmailListener implements ApplicationListener<EmailEvent> {

    @Override
    public void onApplicationEvent(EmailEvent event) {
        System.out.println(event);
        System.out.println("邮件内容:" + event.getText());
        System.out.println("邮件地址:" + event.getAddress());
    }
}

测试事件和监听器;

//------------------------------ ListenerController ----------------------------
@Controller
@ResponseBody
@RequestMapping("/listener")
public class ListenerController {

    @Autowired
    private ListenerService listenerService;

    @RequestMapping("/01")
    public String testEmailListener() {
        listenerService.testListener();
        return "ok";
    }
    
}




// ------------------------------ ListenerService ----------------------------
@Service
public class ListenerService implements ApplicationContextAware {

    private ApplicationContext context;

    public void testListener() {
        EmailEvent emailEvent = new EmailEvent(this, "jx", "zengqiang");
        context.publishEvent(emailEvent);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }
}

调用 /listener/01 接口,运行结果如下:

com.example.myspringpro.listener.EmailEvent[source=com.example.myspringpro.service.ListenerService@7e2e5794]
邮件内容:zengqiang
邮件地址:jx

三. ApplicationListener原理

我们以 ContextRefreshEvent 事件来看 ApplicationListener 的原理;

1. AbsApplicationContext#refresh()

AbstractApplicationContext 的 refresh() 刷新容器;

@Override
public void refresh() throws BeansException, IllegalStateException {

    synchronized (this.startupShutdownMonitor) {
        StartupStep contextRefresh = 
            this.applicationStartup.start("spring.context.refresh");

        prepareRefresh();

        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        prepareBeanFactory(beanFactory);

        try {

            postProcessBeanFactory(beanFactory);

            StartupStep beanPostProcess = 
                this.applicationStartup.start("spring.context.beans.post-process");

            invokeBeanFactoryPostProcessors(beanFactory);

            registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();

            initMessageSource();

            // 1.初始化ApplicationEventMulticaster
            initApplicationEventMulticaster();

            onRefresh();

            // 2.往容器中注入所有的 ApplicationListener
            registerListeners();

            finishBeanFactoryInitialization(beanFactory);

            // 3.容器刷新完成,发布ContextRefreshEvent事件
            finishRefresh();
        } catch (BeansException ex) {
            
        } finally {
            resetCommonCaches();
            contextRefresh.end();
        }
    }
}

1.1 initApplicationEventMulticaster()

  1. 先去容器中找有没有 id = “applicationEventMulticaster” 的组件;
  2. 如果没有的话,this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory),并将该 applicationEventMulticaster 注入到容器中;
protected void initApplicationEventMulticaster() {
   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
      this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, 
                                ApplicationEventMulticaster.class);
   }
   else {
      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, 
                                    this.applicationEventMulticaster);
   }
}

1.2 registerListeners()

往容器中注入所有的 ApplicationListener,往 ApplicationEventMulticaster 中添加所有的监听器;

protected void registerListeners() {
    // Register statically specified listeners first.
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 往 ApplicationEventMulticaster 中添加所有的监听器
    // 后处理器会初始化这些监听器
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().
            addApplicationListenerBean(listenerBeanName);
    }

    // Publish early application events now that we finally have a multicaster...
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

1.3 finishRefresh()

容器刷新完成,并发布 ContextRefreshedEvent 事件;

核心方法 publishEvent(),我们可以重点看一下该接口;

protected void finishRefresh() {
    this.initLifecycleProcessor();
    
    this.getLifecycleProcessor().onRefresh();
    
    // 发布ContextRefreshedEvent事件
    this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
    
    LiveBeansView.registerApplicationContext(this);
}

2. AbsApplicationContext#publishEvent()

AbstractApplicationContext 的 publishEvent() 如下;

public void publishEvent(ApplicationEvent event) {
    // 事件类型为null
    publishEvent(event, null);
}
protected void publishEvent(Object event, ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");

    // 将事件装饰为ApplicationEvent
    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent) 
                         applicationEvent).getResolvableType();
        }
    }

    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    } else {
        // 核心方法
        // getApplicationEventMulticaster()获取事件的多播器
        // 一般为 SimpleApplicationEventMulticaster,调用它的 multicastEvent()
        getApplicationEventMulticaster().multicastEvent(applicationEvent);
    }

    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent)
            .publishEvent(event, eventType);
        } else {
            this.parent.publishEvent(event);
        }
    }
}

3. SimpleApplicationEventMulticaster

默认的事件多播器:SimpleApplicationEventMulticaster;

AbstractApplicationContext 的 publishEvent() 会调用到 multicastEvent();

3.1 multicastEvent()

public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : 
                           resolveDefaultEventType(event));
    // 如果有 Executor 的话,可以使用线程池的 execute() 执行 onApplicationEvent()
    // 默认情况下 executor == null,会通过当前线程执行 onApplicationEvent()
    Executor executor = getTaskExecutor();
    
    // getApplicationListeners(event, type) 获取当前 event 的 ApplicationListener
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        } else {
            // 调用执行listener
            invokeListener(listener, event);
        }
    }
}



protected void invokeListener(ApplicationListener<?> listener,
                              ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        } catch (Throwable err) {
            errorHandler.handleError(err);
        }
    } else {
        // 调用执行listener
        doInvokeListener(listener, event);
    }
}




private void doInvokeListener(ApplicationListener listener, 
                              ApplicationEvent event) {
    try {
        // 执行ApplicationListener的onApplicationEvent()
        listener.onApplicationEvent(event);
    } catch (ClassCastException ex) {
        throw ex;
    }
}
  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值