Spring启动流程解析-8-初始化事件广播

一,Spring启动流程概述

 

Spring的IoC容器在实现控制反转和依赖注入的过程中,可以划分为两个阶段:

  • 容器启动阶段

  • Bean实例化阶段

容器初始化

  1. 加载配置

  2. 分析配置信息

  3. 将Bean信息装配到BeanDefinition

  4. 将Bean信息注册到相应的BeanDefinitionRegistry

  5. 其他后续处理

容器实例化

  1. 根据策略实例化对象

  2. 装配依赖

  3. Bean初始化前处理

  4. 对象初始化

  5. 对象其他处理

  6. 注册回调接口

二,Spring启动流程详解

初始化事件广播

protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    // 检查配置中是否有applicationEventMulticaster的Bean定义
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        // 如果有则获取(实例化Bean)
        this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        // 如果没有手动创建SimpleApplicationEventMulticaster的实例
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        // 把创建的SimpleApplicationEventMulticaster注册到BeanFactory
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                         APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                         "': using default [" + this.applicationEventMulticaster + "]");
        }
    }
}

ApplicationContext中的事件处理是通过ApplicationEvent抽象类和ApplicationListener接口实现的。将实现ApplicationListener接口的Bean部署到上下文中,那么每次将ApplicationEvent发布到ApplicationContext时,该Bean都会得到通知。本质上,这是标准的观察者设计模式。

观察者模式

  • Subject:抽象主题类。保存对所有观察者对象的引用,每个主题都可以有任意数量的观察者。该接口可以添加和删除观察者对象

  • ConcreteSubject:具体主题。将状态保存到具体观察者对。在主题内部发生改变时,给所有登记的观察者发出通知。

  • Observer:抽象观察者。为所有具体的观察者定义接口,在得到主题通知时更新自己。

  • ConcreteObserver:具体观察者。实现更新接口,以使自身状态和主题状态同步。

具体实现

抽象被观察者接口

public interface Subject {
    // 添加观察者
    public void addObserver(Observer o);
    // 删除观察者
    public void removeObserver(Observer o);
    // 通知观察者
    public void notifyObserver();
}

抽象观察者接口

public interface Observer {
    // 当被观察者调用notify()方法时,观察者的update()方法会被回调
    public void update(String message);
}

定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。

/**
 * 被观察者
 * 实现了Subject接口,对Subject接口的三个方法进行了具体实现
 */
public class ConcreteSubject implements Subject {
    
    // 保存观察者的集合
    private List<Observer> list;
    private String message;
    
    public ConcreteSubject() {
        list = new ArrayList<Observer>();
    }
    
    @Override
    public void addObserver(Observer o) {
        list.add(o);
    }
    
    @Override
    public void removeObserver(Observer o) {
        if(!list.isEmpty())
            list.remove(o);
    }

    //遍历
    @Override
    public void notifyObserver() {
        for(int i = 0; i < list.size(); i++) {
            Observer oserver = list.get(i);
            oserver.update(message);
        }
    }
    
    public void setMessage(String s) {
        this.message = s;
        System.out.println("服务消息: " + s);
        //消息更新,通知所有观察者
        notifyObserver();
    }
}

具体观察者

public class User implements Observer {

    private String name;
    private String message;
    
    public User(String name) {
        this.name = name;
    }
    
    @Override
    // 实现update方法
    public void update(String message) {
        this.message = message;
        read();
    }

    public void read() {
        System.out.println(name + " 收到推送消息: " + message);
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        ConcreteSubject cs = new ConcreteSubject();

        Observer user1 = new User("Zhangsan");
        Observer user2 = new User("Lisi");
        Observer user3 = new User("Wangwu");

        cs.addObserver(user1);
        cs.addObserver(user2);
        cs.addObserver(user3);
        cs.setMessage("发布了消息1");

        System.out.println("----------------------------------------------");
        cs.removeObserver(userZhang);
        cs.setMessage("发布了消息2");
    }
}

事件驱动机制

事件驱动的常见形式便是发布-订阅模式。

在跨进程的通信间,我们通常采用引入 MQ (消息队列) 来实现消息的发布和订阅。目前主流应用的架构中,均采用消息的发布-订阅模式来进行大型分布式系统的解耦。使得数据生产方和使用方分离,同时 MQ 还可起到削峰等作用。

同一进程内很多时候也需要这种事件驱动机制来进行逻辑解耦。

事件机制主要由三个部分组成:

  • 事件对象:事件实体。封装事件源对象和事件,在事件源和监听器之间传递信息

  • 监听器:监听事件对象。事件发生时处理回调

  • 事件源:事件发生的起源。注册监听,对事件进行响应。

Java的事件机制

Java 提供了事件相关的接口定义:

  • 事件对象:EventObject 自定义事件对象需要继承该类

  • 监听器:EventListener 事件监听器接口

  • 事件源:不需要实现任何接口,Java 中也没给出相应的定义

示例

事件对象

public class JDKEventObject extends EventObject {

    private Object source;

    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public JDKEventObject(JDKEventSource source) {
        super(source);
        this.source = source;
    }

    @Override
    public Object getSource() {
        return source;
    }
}

监听器

public interface JDKEventListener extends EventListener {
    public void handleEvent(JDKEventObject event);
}

事件源

public class JDKEventSource {
    private Set<EventListener> listeners = new HashSet();

    private String message;

    public void addListener(EventListener event) {
        listeners.add(event);
    }

    public void removeListener(EventListener event) {
        if (listeners.contains(event))
            listeners.remove(event);
    }

    public void fireEvent() {
        Iterator<EventListener> iter = listeners.iterator();
        while (iter.hasNext()) {
            JDKEventListener listener = (JDKEventListener) iter.next();
            listener.handleEvent(new JDKEventObject(this));
        }
    }
}

测试类

public class JDKEventTest {
    public static void main(String[] args) {
        JDKEventSource eventSource = new JDKEventSource();

        eventSource.addListener(new JDKEventListener() {
            @Override
            public void handleEvent(JDKEventObject event) {
                System.out.println("事件1......");
            }
        });
        eventSource.addListener(new JDKEventListener() {
            @Override
            public void handleEvent(JDKEventObject event) {
                System.out.println("事件2......");
            }
        });
        eventSource.fireEvent();
    }
}

事件处理机制在某种程度上与发布-订阅模式非常相似,事件监听器的角色与观察者类似,事件源则充当了被观察对象。事件源状态触发后,主动发起通知给监听器,监听器完成各种后续处理。

Spring事件机制

Spring内置事件:

事件类

说明

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应用程序。

容器生命周期

BeanPostProcessor及Bean的初始和销毁回调这些事件都是建立在容器已经成功启动的基础上,如果我们想在容器本身的生命周期。

// 生命周期接口,任何Spring管理的对象都可以实现该接口
public interface Lifecycle {
    void start();
    void stop();
    boolean isRunning();
}

// 管理ApplicationContext生命周期
public interface LifecycleProcessor extends Lifecycle {
    void onRefresh();
    void onClose();
}

public interface SmartLifecycle extends Lifecycle, Phased {
    // Lifecycle Bean是否自动启动
    boolean isAutoStartup();

    // 停止的时候执行回调,默认超时时间30秒
    void stop(Runnable callback);
}

// Phased最小的对象首先启动,停止时,顺序和启动时相反
public interface Phased {
    // SmartLifecycle的实现类默认Phase为0
    int getPhase();
}

常规的Lifecycle接口只在容器上下文显式的调用start()/stop()方法时,才会去回调Lifecycle实现类的start/stop方法逻辑。并不意味着在上下文刷新时自动启动。

另外,LifeCycle Bean在销毁之前不能保证会收到停止通知。正常关闭时,所有Lifecycle Bean在销毁回调之前首先会收到停止通知,但是在上下文的生命周期内进行热刷新或中止刷新尝试时,只会调用destroy方法。

// 实现Lifecycle的测试类
public class TestLifeCycle implements Lifecycle {

    private boolean running = false;

    public TestLifeCycle() {
        System.out.println("TestLifeCycle.......");
    }

    @Override
    public void start() {
        System.out.println("TestLifeCycle.start().......");
        running = true;
    }

    @Override
    public void stop() {
        System.out.println("TestLifeCycle.start().......");
        running = false;
    }

    @Override
    public boolean isRunning() {
        return running;
    }
}

// 实现SmartLifecycle的测试类
public class TestSmartLifecycle implements SmartLifecycle {

    private boolean running = false;

    public TestSmartLifecycle() {
        System.out.println("TestSmartLifecycle.......");
    }

    @Override
    public boolean isAutoStartup() {
        return true;
    }

    @Override
    public int getPhase() {
        return 10000;
    }

    @Override
    public void start() {
        System.out.println("TestSmartLifecycle.start().......");
        running = true;
    }

    @Override
    public void stop() {
        System.out.println("TestSmartLifecycle.stop().......");
        running = false;
    }

    @Override
    public void stop(Runnable callback) {
        System.out.println("TestSmartLifecycle.stop(Runnable callback).......");
        running = false;
    }

    @Override
    public boolean isRunning() {
        return running;
    }
}

事件机制

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

类名

描述

ApplicationEvent

Spring提供的事件类,继承自 EventObject 类

ApplicationListener

事件监听者,该类接收一个泛型,供 ApplicationEventPublisher 在发布事件时选择 EventListener

ApplicationEventPublisher

封装事件发布功能的接口,通知所有在 Spring 中注册的该事件的监听者进行处理

ApplicationEventPublisherAware

Spring 提供的 Aware 接口之一,实现该接口的 Bean 可以获取 ApplicationEventPublisher 并进行发布事件

ApplicationEventMulticaster

管理多个ApplicationListener对象并向其发布事件的接口

示例

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

服务类

// Spring容器检测到Service实现了ApplicationEventPublisherAware接口,会自动调用setApplicationEventPublisher
public class SpringService implements ApplicationEventPublisherAware {

    private List<String> nameList;
    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void setNameList(List<String> list) {
        this.nameList = list;
    }

    // 要发布自定义ApplicationEvent,需要在ApplicationEventPublisher上调用publishEvent方法
    public void sendMessage(String name) {
        if (nameList.contains(name)) {
            publisher.publishEvent(new SpringEvent(this, name));
            return;
        }
    }
}

监听器

// 要接收自定义的ApplicationEvent,需要实现ApplicationListener监听器
public class SpringListener implements ApplicationListener<SpringEvent> {

    String notifier;

    public void setNotifier(String notifier) {
        this.notifier = notifier;
    }

    @Override
    public void onApplicationEvent(SpringEvent event) {
        System.out.println("onApplicationEvent: "+ notifier);
    }
}

事件类

public class SpringEvent extends ApplicationEvent {

    String name;

    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public SpringEvent(Object source, String name) {
        super(source);
        this.name = name;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值