Spring事件轻松实现观察者模式

Spring框架自带了事件监听机制,可以轻松实现观察者模式。在Spring / Spring Boot框架中内置了许多事件,同时开发者也可基于这些自定义发布应用程序事件。其中主要涉及以下几个核心类与接口。


1.ApplicationEvent应用程序事件

ApplicationEvent应用程序事件是一个抽象类,相当于观察者模式中的观察目标。ApplicationEvent源码如下:

package org.springframework.context;

import java.time.Clock;
import java.util.EventObject;

public abstract class ApplicationEvent extends EventObject {

    /** use serialVersionUID from Spring 1.2 for interoperability. */
    private static final long serialVersionUID = 7099057708183571937L;

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

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

    public ApplicationEvent(Object source, Clock clock) {
        super(source);
        this.timestamp = clock.millis();
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}

ApplicationEvent继承自java.util.EventObject事件对象类,Spring框架中所有事件都继承自ApplicationEvent抽象类,是所有事件的父类。
ApplicationEvent主要的核心是构造函数,它可以初始化一个source事件关联对象,以便在事件监听器中获取并通知更新。


2.ApplicationListener应用程序事件监听器

ApplicationListener应用程序事件监听器是一个接口,相当于观察者模式中的观察者。ApplicationListener源码如下:

package org.springframework.context;

import java.util.EventListener;
import java.util.function.Consumer;

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

   /**
    * Handle an application event.
    * @param event the event to respond to
    */
    void onApplicationEvent(E event);

    static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
        return (event) -> {
            consumer.accept(event.getPayload());
        };
    }
}

ApplicationListener继承自java.util.EventListener事件监听接口,ApplicationListener接口中只定义了一个void onApplicationEvent(E event)方法。当指定监听的事件被发布后就会被触发执行,可以通过event获取事件中的关联对象。


3.ApplicationEventPublisher应用事件发布者

ApplicationEventPublisher应用程序事件发布接口,封装了事件发布的基础功能。ApplicationEventPublisher 接口源码如下:

package org.springframework.context;

@FunctionalInterface
public interface ApplicationEventPublisher {

   /**
    * Notify all <strong>matching</strong> listeners registered with this
    * application of an application event. Events may be framework events
    * (such as ContextRefreshedEvent) or application-specific events.
    * <p>Such an event publication step is effectively a hand-off to the
    * multicaster and does not imply synchronous/asynchronous execution
    * or even immediate execution at all. Event listeners are encouraged
    * to be as efficient as possible, individually using asynchronous
    * execution for longer-running and potentially blocking operations.
    * @param event the event to publish
    * @see #publishEvent(Object)
    * @see org.springframework.context.event.ContextRefreshedEvent
    * @see org.springframework.context.event.ContextClosedEvent
    */
    default void publishEvent(ApplicationEvent event) {
        this.publishEvent((Object)event);
    }

   /**
    * Notify all <strong>matching</strong> listeners registered with this
    * application of an event.
    * <p>If the specified {@code event} is not an {@link ApplicationEvent},
    * it is wrapped in a {@link PayloadApplicationEvent}.
    * <p>Such an event publication step is effectively a hand-off to the
    * multicaster and does not imply synchronous/asynchronous execution
    * or even immediate execution at all. Event listeners are encouraged
    * to be as efficient as possible, individually using asynchronous
    * execution for longer-running and potentially blocking operations.
    * @param event the event to publish
    * @since 4.2
    * @see #publishEvent(ApplicationEvent)
    * @see PayloadApplicationEvent
    */
    void publishEvent(Object event);

}

ApplicationEventPublisher中定义了一个默认的接口方法和和普通接口方法,普通接口方法需要由具体子类容器实现。


4.ApplicationContext应用程序上下文

ApplicationContextSpring中的核心容器之一。ApplicationContext接口继承了ApplicationEventPublisher接口,所以可以使用ApplicationContext接口来发布事件。

以上所说的Spring事件监听发布,通过ApplicationEventPublisher或者ApplicationContext容器发布事件,使用ApplicationEvent关联事件对象。然后ApplicationListener监听该事件。当事件发布后,监听器就会监听到事件的发布,并获取到事件关联对象。


5.Spring观察者模式实战

首先创建一个Spring Boot工程。然后创建事件实体:

public class EventBO {

    private String name;

    public EventBO(){}

    public EventBO(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "EventBO{" +
                "name='" + name + '\'' +
                '}';
    }

}

创建应用事件:

public class TestApplicationEvent extends ApplicationEvent {

    public TestApplicationEvent(EventBO eventBO) {
        super(eventBO);
    }

}

创建事件监听器:

@Component
public class TestApplicationListener implements ApplicationListener<TestApplicationEvent> {

    @Override
    public void onApplicationEvent(TestApplicationEvent event) {
        EventBO source = (EventBO) event.getSource();
        System.out.println("Hello " + source.getName() + " this is Spring Application Event!");
    }

}

创建应用上下文:

@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (ApplicationContextHolder.applicationContext == null) {
            ApplicationContextHolder.applicationContext = applicationContext;
        }
    }

    public static <T> void publishEvent(T applicationEvent) {
        applicationContext.publishEvent(applicationEvent);
    }

}

Controller中声明一个接口用于手动触发事件:

@RestController
public class HelloWorldController {

    @GetMapping("event/{name}")
    public void event(@PathVariable("name") String name) {
        ApplicationContextHolder.publishEvent(new TestApplicationEvent(new EventBO(name)));
    }

}

启动工程后请求接口http://127.0.0.1:9096/event/kapcb,控制台输出如下:

Hello kapcb this is Spring Application Event!

利用Spring中的事件监听机制可以轻松实现观察者模式,观察目标也不需要维护观察者列表。相当于发布 - 订阅模式。两者之间是完全解耦的,但是每个观察者都需要在Spring中创建一个Bean

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值