Spring事件机制 ApplicationEventPublisher

目录

1、观察者模式

2、Spring中的观察者

2.1、事件(ApplicationEvent)

2.2、事件发布(ApplicationContext)

2.3、事件监听(ApplicationListener)

2.4、事件管理(ApplicationEventMulticaster)

3、demo

3.1、事件任务类

3.2、事件

3.3、事件监听器

3.3.1、继承ApplicationListener接口

3.3.2、@EventListener注解

3.4、事件发布

3.5、启动类

3.6、注意事项

4、原理简介

4.1、广播器

4.2、注册广播器和监听器

4.2.1、初始化事件广播器(initApplicationEventMulticaster)

4.2.2、注册监听器(registerListeners)

4.3、事件广播

4.3.1、publistEvent

4.3.2、multicastEvent


1、观察者模式

        包含观察者和目标(被观察者)两种对象。

        目标和观察者之间存在一对多的关系,通过建立目标与观察者之间的联系,当目标的某个状态发生变化时,所有与之关联的观察者都会得到通知并执行各自的任务。

也叫作发布-订阅模式:

  • 订阅:观察者向目标对象注册自己,告诉目标对象自己在观察它。
  • 发布:当目标对象的状态发生改变时,向它所有的观察者发送通知,观察者收到通知后执行各自的操作。

优点:降低了目标与观察者之间的耦合关系。

缺点:目标与观察者之间没有完全解耦,还可能出现循环引用;当观察者对象很多时,通知的发布可能会很耗时。

2、Spring中的观察者

2.1、事件(ApplicationEvent)

事件本身,ApplicationEvent是所有事件的弗雷,可以用来传递数据。
Spring内置事件如下:

  • ContextRefreshedEvent: ApplicationContext初始化或刷新,或者说在容器实例化(refresh())时发布事件;
  • ContextStartedEvent:Spring容器启动时,即调用ConfigurableApplicationContext接口的start()时发布事件;
  • ContextStoppedEvent:Spring容器停止时,即调用ConfigurableApplicationContext接口的stop()时发布事件,关闭的容器可以通过start()重启;
  • ContextClosedEvent:Spring容器关闭时,即调用ConfigurableApplicationContext接口的close()时发布事件,所有的Bean已被销毁,无法重启容器;
  • RequestHandledEvent:当一个请求被处理完成时发布事件。

2.2、事件发布(ApplicationContext)

        通过ApplicationEventPublisher中的publishEvent发布事件。

2.3、事件监听(ApplicationListener)

        观察者,监听事件。事件发布后,会通知观察者执行监听器中的业务逻辑。

2.4、事件管理(ApplicationEventMulticaster)

  • 用于事件监听器的注册和事件的广播。
  • 注册:将监听器与事件关联。
  • 广播:事件发布后,通知与事件关联的所有监听器。

3、demo

3.1、事件任务类

/**
 * 用户
 */
@Data
@Builder
public class User {
    private String name;
    private int age;
}

3.2、事件

/**
 * 用戶注册事件
 */
@Getter
public class UserRegisterEvent extends ApplicationEvent{

    private User user;

    public UserRegisterEvent(User user) {
        super("user-register-event");
        this.user = user;
    }
}

3.3、事件监听器

3.3.1、继承ApplicationListener接口

/**
 * 继承ApplicationListener接口监听事件
 * 监听器:当有用户注册事件发生时,记录日志
 */
@Component
@Slf4j
public class RecordUserRegisterListener implements ApplicationListener {    @Async
    @SneakyThrows
    @Override
    public void onApplicationEvent(UserRegisterEvent event) {
        User user = event.getUser();
        Thread.sleep(3000L);
        log.info("用户[" + user.getName() + "]注册成功,记录日志");
    }
}

3.3.2、@EventListener注解

/**
 * @EventListener注解监听事件
 */
@Component
@Slf4j
public class GlobalEventListener {

    @EventListener(classes = UserRegisterEvent.class, condition = "#event.user.age >= 18")
    public void onUserGrant1(UserRegisterEvent event) {
        User user = event.getUser();
        log.info("用户[" + user.getName() + "]注册成功,年龄[" + user.getAge() + "]>=18,授予成人权限");
    }

    @EventListener(classes = UserRegisterEvent.class, condition = "#event.user.age < 18")
    public void onUserGrant2(UserRegisterEvent event) {
        User user = event.getUser();
        log.info("用户[" + user.getName() + "]注册成功,年龄[" + user.getAge() + "]<18,授予未成年权限");
    }}

3.4、事件发布

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @Autowired
    private ApplicationEventPublisher publisher;

    @GetMapping("/register")
    public void register(String name, int age) {
        User user = User.builder().name(name).age(age).build();
        // 事件发布
        publisher.publishEvent(new UserRegisterEvent(user));
        log.info("用户[" + user.getName() + "]注册完成");
    }
}

3.5、启动类

@SpringBootApplication
@EnableAsync
@EnableTransactionManagement
public class BootstrapApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootstrapApplication.class, args);
    }
}

3.6、注意事项

  • 事务监听器

            @EnableTransactionManagement开启事务支持,@TransactionalEventListener标识事务监听器。
            发布事件的操作必须在事务(@Transactional)内进行,否则监听器不会生效,除非将fallbackExecution标志设置为true(@TransactionalEventListener(fallbackExecution = true))
            可以配置在事务的哪个阶段来监听事务(默认在事务提交后监听),@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)。

  • 异步支持

            @EnableAsync开启异步支持,@Async标识监听器异步处理。
            开启异步执行后,方法的异常不会抛出,只能在方法内部处理。

  • 监听器顺序

            @Order控制多个监听器的执行顺序,值越小,监听器越先执行。

4、原理简介

4.1、广播器

  • ApplicationEventMulticaster接口:提供了添加/移除监听器以及广播事件给监听器的行为。
  • AbstractApplicationEventMulticaster抽象类:提供了基础的监听器注册/移除以及查找能力。
  • SimpleApplicationEventMulticaster类:提供了事件广播功能。

4.2、注册广播器和监听器

Spring容器初始化时,在refresh()方法中,会进行广播器和监听器的注册。

4.2.1、初始化事件广播器(initApplicationEventMulticaster)

public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        simpleApplicationEventMulticaster.setApplicationStartup(getApplicationStartup());
        this.applicationEventMulticaster = simpleApplicationEventMulticaster;        
        // 将事件广播器作为单例bean注册到BeanFactory中
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                    "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

4.2.2、注册监听器(registerListeners)

protected void registerListeners() {
    // 获取监听器然后注册到广播器中
    for (ApplicationListener listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 获取bean Name数组String[] listenerBeanNames 然后注册到广播器中
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    Set earlyEventsToProcess = this.earlyApplicationEvents;

    // 处理以前的事件,先将 earlyApplicationEvents 赋予null,然后判断 earlyEventsToProcess 如果不为空就广播出去
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

4.3、事件广播

通过ApplicationEventPublisher的publishEvent方法将事件广播出去。

4.3.1、publistEvent

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    Assert.notNull(event, "Event must not be null");

    ApplicationEvent applicationEvent;
    if (event instanceof ApplicationEvent) {
        applicationEvent = (ApplicationEvent) event;
    }
    else {
        applicationEvent = new PayloadApplicationEvent<>(this, event);
        if (eventType == null) {
            eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
        }
    }

    //如果早期事件不为null,则将事件放入早期事件集合中--说明广播器还没有实例化好
    if (this.earlyApplicationEvents != null) {
        this.earlyApplicationEvents.add(applicationEvent);
    }
    else {
        // 获取广播器进行事件广播
        getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
    }

    //将事件也交给父类处理
    if (this.parent != null) {
        if (this.parent instanceof AbstractApplicationContext) {
            ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
        }
        else {
            this.parent.publishEvent(event);
        }
    }
}

4.3.2、multicastEvent

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    // 解析事件类型
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 尝试获取任务执行器
    Executor executor = getTaskExecutor();
    
    // 获取合适的ApplicationListener,循环调用监听器的onApplicationEvent方法
    for (ApplicationListener listener : getApplicationListeners(event, type)) {
        // 判断executor 是否不为null
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        // 判断applicationStartup 
        else if (this.applicationStartup != null) {
            StartupStep invocationStep = this.applicationStartup.start("spring.event.invoke-listener");
            invokeListener(listener, event);
            invocationStep.tag("event", event::toString);
            if (eventType != null) {
                invocationStep.tag("eventType", eventType::toString);
            }
            invocationStep.tag("listener", listener::toString);
            invocationStep.end();
        }
        else {
            // 否则,直接调用listener.onApplicationEvent,内部通过反射调用监听器方法
            invokeListener(listener, event);
        }
    }
}

以上内容为个人学习理解,如有问题,欢迎在评论区指出。

部分内容截取自网络,如有侵权,联系作者删除。

你可能感兴趣的:(Spring,spring)