• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Spring事件机制 ApplicationEventPublisher

武飞扬头像
零点冰.
帮助1

目录

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、事件任务类

  1.  
    /**
  2.  
     * 用户
  3.  
     */
  4.  
    @Data
  5.  
    @Builder
  6.  
    public class User {
  7.  
        private String name;
  8.  
        private int age;
  9.  
    }

3.2、事件

  1.  
    /**
  2.  
     * 用戶注册事件
  3.  
     */
  4.  
    @Getter
  5.  
    public class UserRegisterEvent extends ApplicationEvent{
  6.  
     
  7.  
        private User user;
  8.  
     
  9.  
        public UserRegisterEvent(User user) {
  10.  
            super("user-register-event");
  11.  
            this.user = user;
  12.  
        }
  13.  
    }

3.3、事件监听器

3.3.1、继承ApplicationListener接口

  1.  
    /**
  2.  
     * 继承ApplicationListener接口监听事件
  3.  
     * 监听器:当有用户注册事件发生时,记录日志
  4.  
     */
  5.  
    @Component
  6.  
    @Slf4j
  7.  
    public class RecordUserRegisterListener implements ApplicationListener<UserRegisterEvent> {    @Async
  8.  
        @SneakyThrows
  9.  
        @Override
  10.  
        public void onApplicationEvent(UserRegisterEvent event) {
  11.  
            User user = event.getUser();
  12.  
            Thread.sleep(3000L);
  13.  
            log.info("用户[" user.getName() "]注册成功,记录日志");
  14.  
        }
  15.  
    }
学新通

3.3.2、@EventListener注解

  1.  
    /**
  2.  
     * @EventListener注解监听事件
  3.  
     */
  4.  
    @Component
  5.  
    @Slf4j
  6.  
    public class GlobalEventListener {
  7.  
     
  8.  
        @EventListener(classes = UserRegisterEvent.class, condition = "#event.user.age >= 18")
  9.  
        public void onUserGrant1(UserRegisterEvent event) {
  10.  
            User user = event.getUser();
  11.  
            log.info("用户[" user.getName() "]注册成功,年龄[" user.getAge() "]>=18,授予成人权限");
  12.  
        }
  13.  
     
  14.  
        @EventListener(classes = UserRegisterEvent.class, condition = "#event.user.age < 18")
  15.  
        public void onUserGrant2(UserRegisterEvent event) {
  16.  
            User user = event.getUser();
  17.  
            log.info("用户[" user.getName() "]注册成功,年龄[" user.getAge() "]<18,授予未成年权限");
  18.  
        }}
学新通

3.4、事件发布

  1.  
    @RestController
  2.  
    @RequestMapping("/user")
  3.  
    @Slf4j
  4.  
    public class UserController {
  5.  
     
  6.  
        @Autowired
  7.  
        private ApplicationEventPublisher publisher;
  8.  
     
  9.  
        @GetMapping("/register")
  10.  
        public void register(String name, int age) {
  11.  
            User user = User.builder().name(name).age(age).build();
  12.  
            // 事件发布
  13.  
            publisher.publishEvent(new UserRegisterEvent(user));
  14.  
            log.info("用户[" user.getName() "]注册完成");
  15.  
        }
  16.  
    }
学新通

3.5、启动类

  1.  
    @SpringBootApplication
  2.  
    @EnableAsync
  3.  
    @EnableTransactionManagement
  4.  
    public class BootstrapApplication {
  5.  
        public static void main(String[] args) {
  6.  
            SpringApplication.run(BootstrapApplication.class, args);
  7.  
        }
  8.  
    }

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)

  1.  
    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
  2.  
    protected void initApplicationEventMulticaster() {
  3.  
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  4.  
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
  5.  
            this.applicationEventMulticaster =
  6.  
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
  7.  
            if (logger.isTraceEnabled()) {
  8.  
                logger.trace("Using ApplicationEventMulticaster [" this.applicationEventMulticaster "]");
  9.  
            }
  10.  
        }
  11.  
        else {
  12.  
            SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
  13.  
            simpleApplicationEventMulticaster.setApplicationStartup(getApplicationStartup());
  14.  
            this.applicationEventMulticaster = simpleApplicationEventMulticaster;        
  15.  
    // 将事件广播器作为单例bean注册到BeanFactory中
  16.  
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
  17.  
            if (logger.isTraceEnabled()) {
  18.  
                logger.trace("No '" APPLICATION_EVENT_MULTICASTER_BEAN_NAME "' bean, using "
  19.  
                        "[" this.applicationEventMulticaster.getClass().getSimpleName() "]");
  20.  
            }
  21.  
        }
  22.  
    }
学新通

4.2.2、注册监听器(registerListeners)

  1.  
    protected void registerListeners() {
  2.  
        // 获取监听器然后注册到广播器中
  3.  
        for (ApplicationListener<?> listener : getApplicationListeners()) {
  4.  
            getApplicationEventMulticaster().addApplicationListener(listener);
  5.  
        }
  6.  
     
  7.  
        // 获取bean Name数组String[] listenerBeanNames 然后注册到广播器中
  8.  
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  9.  
        for (String listenerBeanName : listenerBeanNames) {
  10.  
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  11.  
        }
  12.  
     
  13.  
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
  14.  
     
  15.  
        // 处理以前的事件,先将 earlyApplicationEvents 赋予null,然后判断 earlyEventsToProcess 如果不为空就广播出去
  16.  
        this.earlyApplicationEvents = null;
  17.  
        if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
  18.  
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
  19.  
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
  20.  
            }
  21.  
        }
  22.  
    }
学新通

4.3、事件广播

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

4.3.1、publistEvent

  1.  
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
  2.  
        Assert.notNull(event, "Event must not be null");
  3.  
     
  4.  
        ApplicationEvent applicationEvent;
  5.  
        if (event instanceof ApplicationEvent) {
  6.  
            applicationEvent = (ApplicationEvent) event;
  7.  
        }
  8.  
        else {
  9.  
            applicationEvent = new PayloadApplicationEvent<>(this, event);
  10.  
            if (eventType == null) {
  11.  
                eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
  12.  
            }
  13.  
        }
  14.  
     
  15.  
        //如果早期事件不为null,则将事件放入早期事件集合中--说明广播器还没有实例化好
  16.  
        if (this.earlyApplicationEvents != null) {
  17.  
            this.earlyApplicationEvents.add(applicationEvent);
  18.  
        }
  19.  
        else {
  20.  
            // 获取广播器进行事件广播
  21.  
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
  22.  
        }
  23.  
     
  24.  
        //将事件也交给父类处理
  25.  
        if (this.parent != null) {
  26.  
            if (this.parent instanceof AbstractApplicationContext) {
  27.  
                ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
  28.  
            }
  29.  
            else {
  30.  
                this.parent.publishEvent(event);
  31.  
            }
  32.  
        }
  33.  
    }
学新通

4.3.2、multicastEvent

  1.  
    @Override
  2.  
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  3.  
        // 解析事件类型
  4.  
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  5.  
        // 尝试获取任务执行器
  6.  
        Executor executor = getTaskExecutor();
  7.  
        
  8.  
        // 获取合适的ApplicationListener,循环调用监听器的onApplicationEvent方法
  9.  
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
  10.  
            // 判断executor 是否不为null
  11.  
            if (executor != null) {
  12.  
                executor.execute(() -> invokeListener(listener, event));
  13.  
            }
  14.  
            // 判断applicationStartup 
  15.  
            else if (this.applicationStartup != null) {
  16.  
                StartupStep invocationStep = this.applicationStartup.start("spring.event.invoke-listener");
  17.  
                invokeListener(listener, event);
  18.  
                invocationStep.tag("event", event::toString);
  19.  
                if (eventType != null) {
  20.  
                    invocationStep.tag("eventType", eventType::toString);
  21.  
                }
  22.  
                invocationStep.tag("listener", listener::toString);
  23.  
                invocationStep.end();
  24.  
            }
  25.  
            else {
  26.  
                // 否则,直接调用listener.onApplicationEvent,内部通过反射调用监听器方法
  27.  
                invokeListener(listener, event);
  28.  
            }
  29.  
        }
  30.  
    }
学新通

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

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhahfh
系列文章
更多 icon
同类精品
更多 icon
继续加载