使用spring框架提供的事件监听机制,实现观察者模式

1、spring事件监听机制介绍

Spring/ Spring Boot 提供了一套事件监听机制,可以实现观察者模式。涉及到的几个核心类和接口如下

1、ApplicationEvent
ApplicationEvent(应用程序事件)它是一个抽象类,相当于观察者模式中的观察目标。

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;


   /**
    * Create a new {@code ApplicationEvent}.
    * @param source the object on which the event initially occurred or with
    * which the event is associated (never {@code null})
    */
   public ApplicationEvent(Object source) {
      super(source);
      this.timestamp = System.currentTimeMillis();
   }


   /**
    * Return the system time in milliseconds when the event occurred.
    */
   public final long getTimestamp() {
      return this.timestamp;
   }

}

ApplicationEvent 主要的核心是类构造器,它可以初始化一个 source 事件关联对象,以便在事件监听器中获取并通知更新。

2、 ApplicationListener
ApplicationListener(应用程序事件监听器)是一个接口,相当于观察者模式中的观察者。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
   void onApplicationEvent(E event);

}

ApplicationListener 继承自 Java 中的 EventListener 事件监听接口,ApplicationListener 类中只有一个 onApplicationEvent 方法,当指定监听的事件被发布后就会被触发执行,可以通过 event 获取事件中的关联对象。

3、 ApplicationEventPublisher
事件发布接口,封装了事件发布功能的基础接口。

public interface ApplicationEventPublisher {

   /**
    * Notify all matching listeners registered with this
    * application of an application event. Events may be framework events
    * (such as ContextRefreshedEvent) or application-specific events.
    * 

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) { publishEvent((Object) event); } /** * Notify all matching listeners registered with this * application of an event. *

If the specified {@code event} is not an {@link ApplicationEvent}, * it is wrapped in a {@link PayloadApplicationEvent}. *

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
ApplicationContext 是 Spring 框架中的核心容器。ApplicationContext 接口继承了 ApplicationEventPublisher 接口,所以可以用 ApplicationContext 发布事件。

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    @Nullable
    String getId();

    String getApplicationName();

    String getDisplayName();

    long getStartupDate();

    @Nullable
    ApplicationContext getParent();

    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

使用的逻辑就是通过 ApplicationEventPublisher 或者 ApplicationContext 容器发布 ApplicationEvent 事件并关联事件对象,然后 ApplicationListener 监听该事件,当事件发布后,监听器就会收执行并获取到事件及关联对象。

2、使用spring事件监听机制实现观察者模式

1、新增被观察者

import lombok.Getter;
import org.springframework.context.ApplicationEvent;

@Getter
public class TestEvent extends ApplicationEvent {


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


}

2、新增观察者

import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;

@RequiredArgsConstructor
public class TestListener implements ApplicationListener<TestEvent> {

    @NonNull
    private String result;

    @Async
    @Override
    public void onApplicationEvent(TestEvent event) {
        // 更新结果
        updateResult(event);
    }

    private void updateResult(TestEvent event) {
        this.result = (String) event.getSource();
        System.out.printf("result更新为:",  this.result );
    }

}

3、新增测试配置类

@Slf4j
@Configuration
public class ObserverConfiguration {

/**
CommandLineRunner 和 ApplicationRunner。他们的执行时机为容器启动完成的时候。
这两个接口中有一个 run 方法,我们只需要实现这个方法即可
*/
    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext context) {
        return (args) -> {
            log.info("发布事件:更新result?");
            context.publishEvent(new TestEvent("最新result"));
        };
    }

    @Bean
    public ReaderListener readerListener1(){
        return new ReaderListener();
    }

}

输出结果为:

result更新为:最新result

3、总结:

实际中的观察者模式应用应该应用于具体业务,比如电商支付场景,在用户支付完后可以发布一个支付事件,然后会有扣减积分,短信通知、赠送优惠券等一系列后续的事件监听器观察者,这样可以实现业务解耦。如果大家有用到消息中间件,其实也是观察者模式中发布订阅模式的概念。利用 Spring 中的事件监听机制可以轻松实现观察者模式,观察目标也不需要维护观察者列表了,相当于发布-订阅模式,它们之间是完全解耦的,需要注意的是每个观察者需要创建一个 Bean

你可能感兴趣的:(spring,观察者模式,java)