Spring源码学习笔记(十、Spring启动流程解析:初始化事件广播 )

目录:

  • 事件广播源码
  • 观察者模式
  • Java事件机制
  • Spring事件驱动机制
  • 容器生命周期

事件广播源码

Spring初始化事件广播的源码很简单,和上一节初始化消息源的逻辑非常相似,我把代码贴在这。

 1 protected void initApplicationEventMulticaster() {
 2     ConfigurableListableBeanFactory beanFactory = getBeanFactory();
 3     // 检查配置中是否有applicationEventMulticaster的Bean定义
 4     if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
 5         // 如果有则获取(实例化Bean)
 6         this.applicationEventMulticaster =
 7             beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
 8         if (logger.isDebugEnabled()) {
 9             logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
10         }
11     }
12     else {
13         // 如果没有手动创建SimpleApplicationEventMulticaster的实例
14         this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
15         // 把创建的SimpleApplicationEventMulticaster注册到BeanFactory
16         beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
17         if (logger.isDebugEnabled()) {
18             logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
19                          APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
20                          "': using default [" + this.applicationEventMulticaster + "]");
21         }
22     }
23 }

观察者模式

要想了解Spring和Java的事件机制你就得先了解下什么是观察者模式。我在这里简述下,观察者模式中主要分为三个元素,事件、观察者、被观察者,也可以叫做事件对象、事件源、监听器

我你举个例方便你理解,就以最简单且常见的吃饭排号来说吧:

  • 你一天中午去吃黄焖鸡,点完餐后服务员把你的排号给到了你,当你的黄焖鸡做好了后服务员便会大喊,多少号的黄焖鸡做好了,请到前台取餐之类的话术。
  • 此时你听到叫到你的号了,便会去前台取餐。
  • 在这个场景中:
    • 取餐便是事件
    • 观察者是服务员,当黄焖鸡做好了后就会通知被观察者
    • 被观察者则是食客,也就是你,听到服务员(观察者)叫号后便去取餐(接收观察者的消息通知)。

具体代码实现如下:

https://www.cnblogs.com/bzfsdr/p/12685451.html

Java事件机制

说Java事件机制前首先让我们了解下什么是事件驱动机制:

  • 事件驱动的常见形式便是发布-订阅模式
  • 跨进程的通信间,我们通常采用引入MQ (消息队列) 来实现消息的发布和订阅。目前主流应用的架构中,均采用消息的发布-订阅模式来进行大型分布式系统的解耦。使得数据生产方和使用方分离,同时 MQ 还可起到削峰等作用。
  • 同一进程内很多时候也需要这种事件驱动机制来进行逻辑解耦
  • 事件机制主要由三个部分组成:
    • 事件对象:事件实体。封装事件源对象和事件,在事件源和监听器之间传递信息。
    • 监听器:监听事件对象。事件发生时处理回调。
    • 事件源:事件发生的起源。注册监听,对事件进行响应。

———————————————————————————————————————————————————————

Java事件机制则是基于观察者模式,定义了如下接口:

  • 事件对象:EventObject自定义事件对象需要继承该类。
  • 监听器:EventListener事件监听器接口。
  • 事件源:不需要实现任何接口,Java中也没给出相应的定义。

具体使用方式:与观察者模式大同小异。

1、事件对象:

 1 public class JDKEventObject extends EventObject {
 2 
 3     private Object source;
 4 
 5     public JDKEventObject(JDKEventSource source) {
 6         super(source);
 7         this.source = source;
 8     }
 9 
10     @Override
11     public Object getSource() {
12         return source;
13     }
14 }

2、监听器:

1 public interface JDKEventListener extends EventListener {
2 
3     public void handleEvent(JDKEventObject event);
4 }

3、事件源:

 1 public class JDKEventSource {
 2 
 3     private Set<EventListener> listeners = new HashSet();
 4 
 5     private String message;
 6 
 7     public void addListener(EventListener event) {
 8         listeners.add(event);
 9     }
10 
11     public void removeListener(EventListener event) {
12         if (listeners.contains(event))
13             listeners.remove(event);
14     }
15 
16     public void fireEvent() {
17         Iterator<EventListener> iter = listeners.iterator();
18         while (iter.hasNext()) {
19             JDKEventListener listener = (JDKEventListener) iter.next();
20             listener.handleEvent(new JDKEventObject(this));
21         }
22     }
23 }

Spring事件驱动机制

Spring事件驱动是基于Java的事件驱动实现的,并且内置了一些时间:

  • ContextRefreshedEvent:ApplicationContext初始化或刷新触发该事件
    • 通常在Spring加载或刷新应用上下文时,同时也想刷新预加载的资源,就可以通过监听ContextRefreshedEvent来做这样的事情
    • 这里的“初始化”是指所有Bean均已加载,检测到并激活了BeanPostProcessors,已预先实例化单例并且可以使用ApplicationContext对象。
    • 只要上下文尚未关闭,选用的ApplicationContext支持这种“热”刷新(如:XmlWebApplicationContext支持热刷新,但GenericApplicationContext不支持),刷新可以被多次触发。
  • ContextStartedEvent:ApplicationContext启动时触发该事件。
    • "Started" 意味着所有Lifecycle Bean会获得启动事件。
    • 通常,此事件用于在显式停止后重新启动Bean时,也可以用于启动尚未配置为自动启动的组件
  • ContextStoppedEvent:ApplicationContext被停止时触发该事件。
    • "Stopped"是指所有Lifecycle Bean都收到一个明确的停止事件。
    • 已停止的上下文可以通过start()调用重新启动
  • ContextClosedEvent:ApplicationContext被关闭时触发该事件。
    • "Closed" 意味着容器管理的所有单例Bean都被销毁
    • 关闭的上下文表示容器生命周期结束,它不能刷新或重新启动
  • RequestHandledEvent:基于Web应用的事件,当一个HTTP请求完成后触发该事件。该事件仅适用于使用DispatcherServlet的Web应用程序

———————————————————————————————————————————————————————

Spring事件机制中除了事件对象和监听者者两个角色之外,“事件广播器”则负责把事件转发给监听者:

  • ApplicationEvent:Spring提供的事件类,继承自EventObject类。
  • ApplicationListener:事件监听者,该类接收一个泛型,供ApplicationEventPublisher在发布事件时选择EventListener。
  • ApplicationEventPublisher:封装事件发布功能的接口,通知所有在Spring中注册的该事件的监听者进行处理。
  • ApplicationEventPublisherAware:Spring提供的Aware接口之一,实现该接口的Bean可以获取ApplicationEventPublisher并进行发布事件。
  • ApplicationEventMulticaster:管理多个ApplicationListener对象并向其发布事件的接口。

Spring 中,不需要我们手动进行监听器注册。ApplicationListener对象一旦在Spring容器中被注册,Spring会进行监听器的注册,实现事件的监听。

1、服务类:

 1 // Spring容器检测到Service实现了ApplicationEventPublisherAware接口,会自动调用setApplicationEventPublisher
 2 public class SpringService implements ApplicationEventPublisherAware {
 3 
 4     private List<String> nameList;
 5     private ApplicationEventPublisher publisher;
 6 
 7     @Override
 8     public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
 9         this.publisher = publisher;
10     }
11 
12     public void setNameList(List<String> list) {
13         this.nameList = list;
14     }
15 
16     // 要发布自定义ApplicationEvent,需要在ApplicationEventPublisher上调用publishEvent方法
17     public void sendMessage(String name) {
18         if (nameList.contains(name)) {
19             publisher.publishEvent(new SpringEvent(this, name));
20             return;
21         }
22     }
23 }

2、监听器:

 1 // 要接收自定义的ApplicationEvent,需要实现ApplicationListener监听器
 2 public class SpringListener implements ApplicationListener<SpringEvent> {
 3 
 4     String notifier;
 5 
 6     public void setNotifier(String notifier) {
 7         this.notifier = notifier;
 8     }
 9 
10     @Override
11     public void onApplicationEvent(SpringEvent event) {
12         System.out.println("onApplicationEvent: "+ notifier);
13     }
14 }

3、事件类:

 1 public class SpringEvent extends ApplicationEvent {
 2 
 3     String name;
 4 
 5     /**
 6      * Create a new ApplicationEvent.
 7      *
 8      * @param source the object on which the event initially occurred (never {@code null})
 9      */
10     public SpringEvent(Object source, String name) {
11         super(source);
12         this.name = name;
13     }
14 }

容器生命周期

之前我们所说的BeanPostProcessorBean的初始和销毁回调这些事件都是建立在容器已经成功启动的基础上,如果我们想在容器启动前后做一些处理就需要实现如下接口:

 1 // 生命周期接口,任何Spring管理的对象都可以实现该接口
 2 public interface Lifecycle {
 3     void start();
 4     void stop();
 5     boolean isRunning();
 6 }
 7 
 8 // 管理ApplicationContext生命周期
 9 public interface LifecycleProcessor extends Lifecycle {
10     void onRefresh();
11     void onClose();
12 }
13 
14 public interface SmartLifecycle extends Lifecycle, Phased {
15     // Lifecycle Bean是否自动启动
16     boolean isAutoStartup();
17 
18     // 停止的时候执行回调,默认超时时间30秒
19     void stop(Runnable callback);
20 }
21 
22 // Phased最小的对象首先启动,停止时,顺序和启动时相反
23 public interface Phased {
24     // SmartLifecycle的实现类默认Phase为0
25     int getPhase();
26 }

示例:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5 
 6     <bean class="com.jdr.spring.event.TestLifeCycle" name="testLifeCycle"/>
 7 
 8     <bean class="com.jdr.spring.event.TestSmartLifeCycle" name="testSmartLifeCycle"/>
 9 
10     <bean class="com.jdr.spring.event.CustomContextEvent" name="customContextEvent"/>
11 
12 </beans>
 1 public class TestLifeCycle implements Lifecycle {
 2 
 3     private boolean running = false;
 4 
 5     public TestLifeCycle() {
 6         System.out.println("TestLifeCycle....");
 7     }
 8 
 9     @Override
10     public void start() {
11         System.out.println("TestLifeCycle start...");
12     }
13 
14     @Override
15     public void stop() {
16         System.out.println("TestLifeCycle stop...");
17     }
18 
19     @Override
20     public boolean isRunning() {
21         return running;
22     }
23 }
 1 public class TestSmartLifeCycle implements SmartLifecycle {
 2 
 3     private boolean running = false;
 4 
 5     public TestSmartLifeCycle() {
 6         System.out.println("TestSmartLifeCycle....");
 7     }
 8 
 9     @Override
10     public boolean isAutoStartup() {
11         // 若自动启动标识为false,则容器启动时不会调用start()
12         return true;
13     }
14 
15     @Override
16     public void stop(Runnable callback) {
17         System.out.println("TestSmartLifeCycle stop callback....");
18         this.running = false;
19     }
20 
21     @Override
22     public void start() {
23         System.out.println("TestSmartLifeCycle start....");
24         this.running = true;
25     }
26 
27     @Override
28     public void stop() {
29         System.out.println("TestSmartLifeCycle stop....");
30         this.running = false;
31     }
32 
33     @Override
34     public boolean isRunning() {
35         return running;
36     }
37 
38     @Override
39     public int getPhase() {
40         return 100;
41     }
42 }
 1 public class CustomContextEvent implements ApplicationListener<ApplicationEvent> {
 2 
 3     @Override
 4     public void onApplicationEvent(ApplicationEvent event) {
 5         if (event instanceof ContextRefreshedEvent) {
 6             System.out.println("ContextRefreshedEvent...");
 7         }
 8         if (event instanceof ContextStartedEvent) {
 9             System.out.println("ContextStartedEvent...");
10         }
11         if (event instanceof ContextStoppedEvent) {
12             System.out.println("ContextStoppedEvent...");
13         }
14         if (event instanceof ContextClosedEvent) {
15             System.out.println("ContextClosedEvent...");
16         }
17     }
18 }

注意:

  • 常规的Lifecycle接口只在容器上下文显式的调用start()/stop()方法时,才会去回调Lifecycle实现类的start/stop方法逻辑。
    • 如果需要在容器启动时调用start()就需要实现SmartLifecycle接口,并且将isAutoStartup设置为true
  • 另外,LifeCycle Bean在销毁之前不能保证会收到停止通知。
    • 正常关闭时,所有Lifecycle Bean在销毁回调之前首先会收到停止通知,但是在上下文的生命周期内进行热刷新或中止刷新尝试时,只会调用destroy方法。
原文地址:https://www.cnblogs.com/bzfsdr/p/13038863.html