前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Spring学习笔记(10)一spring容器事件ApplicationEvent使用

Spring学习笔记(10)一spring容器事件ApplicationEvent使用

作者头像
黄规速
发布2022-04-14 16:09:08
发布2022-04-14 16:09:08
1.3K00
代码可运行
举报
运行总次数:0
代码可运行

一、背景

业务场景:当用户注册后,发送邮件到其邮箱提示用户进行账号激活。

二、ApplicationEvent入门使用

1、自定义一个事件

需要继承 ApplicationEvent:

定义两种事件目的是为下面要说明@EventListener 注解和@TransactionalEventListener 注解的区别。

代码语言:javascript
代码运行次数:0
复制
import org.springframework.context.ApplicationEvent;


public class EventMessage extends ApplicationEvent {
    private String content;//内容
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }

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


public class EventMessage2 {
    private String content;//内容
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }

    public EventMessage2() {

    }
}

2、创建监听器,监听自定义的事件

对于 Spring 容器的一些事件,可以监听并且触发相应的方法。通常的方法有 2 种:

1)、ApplicationListener 接口和

2)、@EventListener 注解和@TransactionalEventListener 注解。

1)ApplicationListener 接口方法:

ApplicationListener通过监听容器中发布的一些事件event,事件发生就会触发监听器的回调,就完成了事件驱动开发.

ApplicationListener是一个泛型接口,泛型的类型必须是 ApplicationEvent 及其子类,只要实现了这个接口,那么当容器有相应的事件触发时,就能触发 onApplicationEvent 方法。

代码语言:javascript
代码运行次数:0
复制
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.transaction.event.TransactionPhase;

@Configuration
public class EventMessageListener
       implements ApplicationListener<EventMessage>  {

    @Autowired
    private  EventService eventService;

    @Override
    //@Async("taskExecutor") //异步线程调用
    //@Transactional(rollbackFor = Exception.class)
    //@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    @TransactionalEventListener(fallbackExecution = true)
    public void onApplicationEvent(EventMessage eventMessage) {
        System.out.println("onApplicationEvent触发================");
        eventService.send(eventMessage);
    }
}

Spring内置事件

1、ContextRefreshedEvent

ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用

2、ContextStartedEvent

当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序

3、ContextStoppedEvent

当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作

4、ContextClosedEvent

当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启

5、RequestHandledEvent

这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件

2) 方法2:@EventListener 注解和

1、)使用@EventListener 注解,实现对任意的方法都能监听事件,通过指定 classes,即需要处理的事件类型。 但是事件定义classes必须要继承ApplicationEvent,否则程序会异常。可以设置多项。

2)@TransactionalEventListener 注解的事件无需要继承ApplicationEvent。例如EventMessage2就是独立的bean。

代码语言:javascript
代码运行次数:0
复制
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.transaction.event.TransactionalEventListener;

@Configuration
public class EventMessageListener2 {

    @EventListener(classes={EventMessage.class})
    @TransactionalEventListener(fallbackExecution = true)
    public void listen(EventMessage event){
        System.out.println("EventListener事件触发:"+event.getClass().getName());
    }


    @TransactionalEventListener(fallbackExecution = true)
    public void listen(EventMessage2 event){
        System.out.println("TransactionalEventListener事件触发:"+event.getClass().getName());
    }
}

3、事件业务逻辑

代码语言:javascript
代码运行次数:0
复制
@Component
public class EventService {
    /**
     * 处理业务
     * @param eventMessage
     */
    public  void send(EventMessage eventMessage) {
        System.out.println("事件业务逻辑eventMessage content:" + eventMessage.getContent());
    }
}

4、ApplicationEventPublisher异步推送事件

代码语言:javascript
代码运行次数:0
复制
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class EventMessagePublisher {
    @Autowired
    private ApplicationEventPublisher  publisher;

    public void send(EventMessage eventMessage) {
        publisher.publishEvent(eventMessage);
    }

    public void send2(EventMessage2 eventMessage) {
        publisher.publishEvent(eventMessage);
    }
}

5、发送事件

代码语言:javascript
代码运行次数:0
复制
    @Autowired
    EventMessagePublisher  eventMessagePublisher;
    @RequestMapping("/testevent/")
    @ResponseBody
    public String testevent() {
        EventMessage eventMessage = new EventMessage(this
        );
        eventMessage.setContent("hello event");
        eventMessagePublisher.send(eventMessage);

        EventMessage2 EventMessage2 = new EventMessage2();
        eventMessagePublisher.send2(EventMessage2);

        return "ok";
    }

三、@TransactionalEventListener和@EventListener

如果我们在事务中完成数据库更新操作后,发布了一个事件EventMessage,如果此时使用的是@EventListener,然后在这个事件EventMessage中,又要对数据进行查询,这时候会发现,查询不到刚才入库的数据,这是因为事务还没提交完成,在同一个事务当中,查询不到才存入的数据,那么就引出了下面的解决方式。

为了解决上述问题,Spring为我们提供了两种方式: (1) @TransactionalEventListener注解。 (2) 事务同步管理器TransactionSynchronizationManager。 以便我们可以在事务提交后再触发某一事件来进行其他操作。

@TransactionalEventListener详解,从命名上直接看出,它就是个EventListener, 在Spring4.2+,通过@TransactionEventListener的方式,能够实现在控制事务的同时,完成对对事件的处理。

我们知道,Spring的事件监听机制(发布订阅模型)实际上并不是异步的(默认情况下),而是同步的来将代码进行解耦。而@TransactionEventListener仍是通过这种方式,但是加入了回调的方式来解决,这样就能够在事务进行Commited,Rollback…等时候才去进行Event的处理,来达到事务同步的目的。

四、监听事件异步

实现方法比较简单,直接在定义的方法上方加@Async()注解就好了。

异步方法可以指定使用某一线程池:如 @Async("taskExecutor"),通过线程池Bean对象名字为taskExecutor来异步执行。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/08/27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、ApplicationEvent入门使用
    • 1、自定义一个事件
    • 2、创建监听器,监听自定义的事件
      • 1)ApplicationListener 接口方法:
      • 2) 方法2:@EventListener 注解和
    • 3、事件业务逻辑
    • 4、ApplicationEventPublisher异步推送事件
    • 5、发送事件
  • 三、@TransactionalEventListener和@EventListener
  • 四、监听事件异步
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档