Spring消息的发布与订阅

       发布与订阅是一种典型的生产者与消费者模型,它可以让服务之间的调用变的更加灵活易扩展,数据共享更加方便,高内聚低耦合,思想很重要,值得学习。

1、事件-监听模型

Spring是基于 事件/监听器编程模型,在这个模型中,有几个重要的角色:
  • 事件:ApplicationEvent
  • 应用事件监听器:ApplicationListener
  • 事件发布者:ApplicationContext[容器上下文]

2、场景实例

  • 场景 一:等Spring容器初始化完成之后,再完成一些耗时的任务,例如 统计工作,数据加载,文件上传等;
  • 场景二:系统检查,容器启动之后立马检查第三方的接口是否OK;
  • 场景三:缓存预热;
  • 场景四:检验数据;
  • 场景五:关闭容器的时候,查看线程池是否执行完毕,勾子函数;

3、Spring消息机制

3.1、Spring事件:ApplicationEvent

Spring中提供的几种标准事件:
ContextRefreshEvent: 当ApplicationContext容器初始化完成或者被刷新的时候,就会发布该事件。此处的容器初始化指的所有的Bean都被成功装载,后处理器(post-processor)Bean被检测到并且被激活,所有的单例Bean都被预实例化,ApplicationContext容器已经可以使用。
ContextStartedEvent: 在spring容器启动后触发的事件,调用ConfigurableApplicationContext中的start()方法的时候执行。在经常需要停止后重新启动的场合比较适用。
ContextStoppedEvent: 当ApplicationContext容器停止的时候发布事件,即调用ConfigurableApplicationContext的close方法的时候。这里的停止是指,所有被容器管理生命周期的Bean接到一个 明确的停止信号
ContextClosedEvent: 当Application关闭的时候发布事件,即调用ConfigurableApplicationContext的close()方法的时候,关闭指的是所有的 单例Bean都被销毁。关闭上下文后,不能重新刷新或者重新启动。

3.2、Spring容器消息事件实现

实践一:利用spring自带的容器消息机制完成一些功能,例如容器启动之后可以做一些耗时的操作:
@Component("userInfoService")
public class UserInfoService implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private CacheService userCache;


    @Override    //当一个ApplicationContext初始化完成时触发该操作
    public void onApplicationEvent(ContextRefreshedEvent event) {
        userCache.updateAllUseinfoList();//spring容器初始化完毕后全量更新用户列表信息;
        System.out.println("spring容易初始化完毕===========================");
    }
}

3.3、Spring自定义消息实现

事件发布者
ApplicationEvent, 容器事件源必须被ApplicationContext发布;
applicationContext.publishEvent(orderInfo);

事件监听者

ApplicationListener, 监听器,可由容器中任何监听器Bean担任。
  • 实现方法一:实现ApplicationListener< T > 接口,自定义监听器,在onApplicationEvent(T t)中实现相应的监听功能;
  • 实现方法二:使用@EventListener 注解,自定义消息handler处理;
注意: 需要在xml中配置相应的广播监听器的线程池,或者使用@EnableAsync异步注解,异步执行,否则是主线程完成任务,不会异步执行;

3.4、实践

模拟订单创建后发布一个订单消息,通知其他的服务进行其他增值业务的处理。

3.4.1、自定义消息的监听

方式一:消息的监听-实现接口  ApplicationListener<T>
@Component 
public class GoodsOrderEventListener implements ApplicationListener<OrderInfo> {

    @Resource
    private AddGoodsService addGoodsService;
    //自定义监听OrderInfo消息
    public void onApplicationEvent(OrderInfo orderInfo) {
        System.out.println("接收到订单信息,开始发送信息:");
        addGoodsService.sendMsg();
    }
}
方式二:使用Spring 的注解:@EventListener实现
//方式二:消息的监听-通过注解@EventListener
@EventListener 
public void handlerOrderEvent(OrderInfo orderInfo) {
    System.out.println("接受到订单消息,执行用户账单信息入库");
    this.insertAccountInfo();
}

3.4.2、自定义消息的发布

@Service
public class OrderBiz implements ApplicationContextAware {

    @Resource
    private AddOrderService addOrderService;

    @Resource
    private ApplicationContext applicationContext;

   //获取applicationContext 也是OK的;
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContextTest = applicationContext;
    }

     //创建订单成功后发布一条订单消息;
    public void createOrder(OrderInfo orderInfo){
        System.out.println("开始下订单:");
        if(addOrderService.addOrderInfo(orderInfo)){
            //todo 事件发布者 发布自己的消息,开始执行增值业务
            applicationContext.publishEvent(orderInfo);
        } else {
            System.out.println("订单创建失败!");
        }   
    }
}

注意:如果是web容器,我们还需要判断一下根容器和子容器的类型,否则会导致该事件被执行两次

@Service
public class InitRunner implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        //root application context
        if (contextRefreshedEvent.getApplicationContext().getParent() == null) { //根容器
            /**
             * 这里既是 root 根容器初始化完毕后,会进入该分支,
             */
            //todo。。。

        }else {//springMVC的容器,子容器,负责controller的扫描工作HandlerMapping
            /**
             * 如果是spring mvc的话, dispatchServlet对应的 applicationContext 会进入这个分支
             */

            ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
            //todo。。。
        }
    }
}

4、SpringBoot中消息类型

类似的SpringBoot也提供了几种消息类型, SpringBoot Application共支持6种事件监听,按顺序分别是:
  • 1. ApplicationStartingEvent:在应用容器最开始启动的时候触发
  • 2. ApplicationEnvironmentPreparedEvent:在容器已准备好上下文但是尚未创建的时候触发;
  • 3. ApplicationPreparedEvent:在Bean定义加载之后、刷新上下文之前触发
  • 4. ApplicationStartedEvent:在刷新上下文之后、容器启动之前触发
  • 5. ApplicationReadyEvent:容器启动完成之后触发
  • 6. ApplicationFailedEvent:在启动Spring发生异常时触发
SpringBoot的容器事件消息的发布/订阅实践
@Slf4j //容器启动完成后执行耗时的数据更新操作。
public class AppRunTask implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
        ConfigurableApplicationContext applicationContext = applicationReadyEvent.getApplicationContext();

        CacheService cacheService = applicationContext.getBean(CacheService.class);
        userCache.updateAllUseinfoList();//更新用户列表信息;

    }
}

5、小结

        Spring的事件监听:为bean之间的消息通信提供支持。当一个bean做完一件事以后,通知另一个bean知晓并做出相应处理,很好的解决了操作和事务之间的通信问题,扩展灵活性强。
        消息机制的通信思想在分布式中也起着举足轻重的作用,消息通信变的更加方便,提高了系统的吞吐量,让系统变的灵活,易扩展。
 
 
 
 
水滴石穿,积少成多。学习笔记,内容简单,用于复习,梳理巩固。
 
 
 
 
 
 
 
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值