zoukankan      html  css  js  c++  java
  • 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方法。
  • 相关阅读:
    了解Onunload,onbeforeunload事件
    asp.net 获取客服端的Ip地址
    HttpWebRequest WebResponse 对象简单了解
    web 编辑word 之dsoframer控件
    web编辑word之dsoframer(二)
    WebClient 对象实现下载和上传
    jquery datagrid 后台获取datatable处理成正确的json字符串
    doc文档的web查看
    C#中处理字符串对象的函数
    类3-类的static属性
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/13038863.html
Copyright © 2011-2022 走看看