# 别再面向 for 循环编程了,Spring 观察者模式就很香

返回:一些 spring 功能实现首页

# Spring 事件监听机制

在 Spring/ Spring Boot 框架中有一套事件监听机制,可以实现观察者模式

# ApplicationEvent

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

package org.springframework.context;

import java.util.EventObject;

/**
 * Class to be extended by all application events. Abstract as it
 * doesn't make sense for generic events to be published directly.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
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 ApplicationEvent.
        * @param source the object on which the event initially occurred (never {@code null})
        */
    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }


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

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

ApplicationEvent 继承自 Java 中的 EventObject 事件对象类,Spring 框架中的所有事件都继承自 ApplicationEvent 类,它是所有事件的父类。

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

# ApplicationListener

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

package org.springframework.context;

import java.util.EventListener;

/**
 * Interface to be implemented by application event listeners.
 * Based on the standard {@code java.util.EventListener} interface
 * for the Observer design pattern.
 *
 * <p>As of Spring 3.0, an ApplicationListener can generically declare the event type
 * that it is interested in. When registered with a Spring ApplicationContext, events
 * will be filtered accordingly, with the listener getting invoked for matching event
 * objects only.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @param <E> the specific ApplicationEvent subclass to listen to
 * @see org.springframework.context.event.ApplicationEventMulticaster
 */
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

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

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

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

# ApplicationEventPublisher

应用程序事件发布接口,封装了事件发布功能的基础接口。

package org.springframework.context;

/**
 * Interface that encapsulates event publication functionality.
 * Serves as super-interface for {@link ApplicationContext}.
 *
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @since 1.1.1
 * @see ApplicationContext
 * @see ApplicationEventPublisherAware
 * @see org.springframework.context.ApplicationEvent
 * @see org.springframework.context.event.EventPublicationInterceptor
 */
@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 RequestHandledEvent) or application-specific events.
        * @param event the event to publish
        * @see org.springframework.web.context.support.RequestHandledEvent
        */
    default void publishEvent(ApplicationEvent event) {
        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}.
        * @param event the event to publish
        * @since 4.2
        * @see PayloadApplicationEvent
        */
    void publishEvent(Object event);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

ApplicationEventPublisher 有一个默认接口方法和接口方法,接口方法需要由具体的子类容器实现。

# ApplicationContext

ApplicationContext 这个类就再熟悉不过了,它是 Spring 框架中的核心容器。

ApplicationContext 接口继承了 ApplicationEventPublisher 接口,所以常用的 ApplicationContext 就可以用来发布事件。

# Spring Boot 观察者模式实战

# 新增观察者目标类

package com.chlm.mysession.event;

import org.springframework.context.ApplicationEvent;

/**
 * @author : htring
 * @packageName : com.chlm.mysession.event
 * @description :
 * @date : 2021/7/14 16:23
 */
public class MyStackEvent extends ApplicationEvent {
    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public MyStackEvent(Object source) {
        super(source);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

实现 Spring 框架中的 ApplicationEvent 应用程序事件接口,相当于是一个观察者目标。

# 新增观察者类

package com.chlm.mysession.event;

import cn.hutool.core.util.ObjectUtil;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;

/**
 * @author : htring
 * @packageName : com.chlm.mysession.event
 * @description :
 * @date : 2021/7/14 16:27
 */
@RequiredArgsConstructor
public class MyStackEventListener implements ApplicationListener<MyStackEvent> {

    @NonNull
    private String name;
    private String article;

    /**
     * Handle an application event.
     *
     * @param event the event to respond to
     */
    @Async
    @Override
    public void onApplicationEvent(MyStackEvent event) {
        updateArticle(event);
    }

    private void updateArticle(MyStackEvent event) {
        this.article = ObjectUtil.toString(event.getSource());
        System.out.printf("我是读者:%s,文章已经更新:%s\n", this.name, this.article);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

实现 Spring 框架中的 ApplicationListener 应用监听接口,相当于是观察者

# 新增测试配置类