zoukankan      html  css  js  c++  java
  • Spring Boot 事件和监听

    Application Events and Listeners

    1、自定义事件和监听

    1.1、定义事件

     1 package com.cjs.boot.event;
     2 
     3 import lombok.Data;
     4 import org.springframework.context.ApplicationEvent;
     5 
     6 @Data
     7 public class BlackListEvent extends ApplicationEvent {
     8 
     9     private String address;
    10 
    11     public BlackListEvent(Object source, String address) {
    12         super(source);
    13         this.address = address;
    14     }
    15 }

    1.2、定义监听

     1 package com.cjs.boot.event;
     2 
     3 import org.springframework.context.ApplicationListener;
     4 import org.springframework.context.event.EventListener;
     5 import org.springframework.stereotype.Component;
     6 
     7 8 public class BlackListListener implements ApplicationListener<BlackListEvent> {
     9 
    10     @Override
    11     public void onApplicationEvent(BlackListEvent event) {
    12         System.out.println("监听到BlackListEvent事件: " + event.getAddress());
    13         try {
    14             Thread.sleep(2000);
    15         } catch (InterruptedException e) {
    16             e.printStackTrace();
    17         }
    18     }
    19 }

    1.3、注册监听

     1 package com.cjs.boot;
     2 
     3 import com.cjs.boot.event.BlackListListener;
     4 import org.springframework.boot.SpringApplication;
     5 import org.springframework.boot.autoconfigure.SpringBootApplication;
     6 import org.springframework.boot.web.server.ErrorPage;
     7 import org.springframework.boot.web.server.ErrorPageRegistrar;
     8 import org.springframework.boot.web.server.ErrorPageRegistry;
     9 import org.springframework.cache.annotation.EnableCaching;
    10 import org.springframework.context.annotation.Bean;
    11 import org.springframework.http.HttpStatus;
    12 import org.springframework.scheduling.annotation.EnableAsync;
    13 
    14 @SpringBootApplication
    15 public class CjsSpringbootExampleApplication {
    16 
    17     public static void main(String[] args) {
    18 
    19         SpringApplication springApplication = new SpringApplication(CjsSpringbootExampleApplication.class);
    20         springApplication.addListeners(new BlackListListener());
    21         springApplication.run(args);
    22 
    23     }

    1.4、发布事件

     1 package com.cjs.boot.controller;
     2 
     3 import com.cjs.boot.event.BlackListEvent;
     4 import org.springframework.beans.factory.annotation.Autowired;
     5 import org.springframework.context.ApplicationContext;
     6 import org.springframework.context.ApplicationEventPublisher;
     7 import org.springframework.web.bind.annotation.GetMapping;
     8 import org.springframework.web.bind.annotation.RequestMapping;
     9 import org.springframework.web.bind.annotation.RestController;
    10 
    11 @RestController
    12 @RequestMapping("/activity")
    13 public class ActivityController {
    14 
    15 //    @Autowired
    16 //    private ApplicationEventPublisher publisher;
    17 
    18     @Autowired
    19     private ApplicationContext publisher;
    20 
    21     @GetMapping("/sayHello.json")
    22     public void sayHello() {
    23 
    24         /**
    25          * You may register as many event listeners as you wish, but note that by default event listeners receive events synchronously.
    26          * This means the publishEvent() method blocks until all listeners have finished processing the event.
    27          */
    28 
    29         BlackListEvent event = new BlackListEvent(this, "abc@126.com");
    30         publisher.publishEvent(event);
    31         System.out.println("事件发布成功");
    32     }
    33 
    34 }

    2、基于注解的事件监听

    package com.cjs.boot.event;
    
    import org.springframework.context.event.EventListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class BlackListListener {
    
        @EventListener
        public void processBlackListEvent(BlackListEvent event) {
            System.out.println(123);
        }
    }
    
    ---
    
    package com.cjs.boot;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class CjsSpringbootExampleApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(CjsSpringbootExampleApplication.class, args);
        }
    
    }

    3、异步监听

    1 @EventListener
    2 @Async
    3 public void processBlackListEvent(BlackListEvent event) {
    4     // BlackListEvent is processed in a separate thread
    5 }

    4、应用

     6 import lombok.extern.slf4j.Slf4j;
     7 import org.springframework.beans.factory.annotation.Autowired;
     8 import org.springframework.context.event.EventListener;
     9 import org.springframework.scheduling.annotation.Async;
    10 import org.springframework.stereotype.Component;
    11 
    12 import java.util.ArrayList;
    13 import java.util.List;
    14 import java.util.concurrent.ExecutionException;
    15 import java.util.concurrent.Future;
    16 import java.util.concurrent.atomic.AtomicInteger;
    17 
    18 /**
    19  * 批量送券
    20  */
    21 @Slf4j
    22 @Component
    23 public class BatchSendCouponListener {
    24 
    25     @Autowired
    26     private CouponPresentLogService couponPresentLogService;
    27 
    28     @Async
    29     @EventListener
    30     public void processBatchSendCouponEvent(BatchSendCouponEvent batchSendCouponEvent) {
    31         Long cpId = batchSendCouponEvent.getCouponPresentId();
    32         log.info("收到BatchSendCouponEvent, cpId={}", cpId);
    33         List<CouponPresentLogEntity> list = couponPresentLogService.selectByPid(cpId);
    34 
    35         handle(cpId, list, 0);
    36     }
    37 
    38     private void handle(Long cpId, List<CouponPresentLogEntity> list, int times) {
    39         if (times >= 2) {
    40             log.info("超过重试次数退出, cpId: {}, 剩余: {}", cpId, list.size());
    41             return;
    42         }
    43 
    44         List<Future<CouponPresentLogEntity>> futureList = new ArrayList<>();
    45 
    46         for (CouponPresentLogEntity entity : list) {
    47             futureList.add(couponPresentLogService.present(entity));
    48         }
    49 
    50         AtomicInteger count = new AtomicInteger(0);
    51         //  收集失败的
    52         List<CouponPresentLogEntity> failList = new ArrayList<>();
    53         for (Future<CouponPresentLogEntity> future : futureList) {
    54             try {
    55                 CouponPresentLogEntity couponPresentLogEntity = future.get();
    56                 if (couponPresentLogEntity.getStatus() != PresentStatusEnum.SUCCESS.getType().intValue()) {
    57                     failList.add(couponPresentLogEntity);
    58                 }
    59                 count.getAndIncrement();
    60                 if (count.intValue() >= list.size()) {
    61                     List<CouponPresentLogEntity> failPresentLogList = couponPresentLogService.selectFailLogByPid(cpId);
    62                     if (null != failPresentLogList && failPresentLogList.size() > 0) {
    63                         times++;
    64                         log.info("第{}次重试, CPID: {}, 总计: {}, 失败: {}", times, cpId, list.size(), failPresentLogList.size());
    65                         handle(cpId, failPresentLogList, times);
    66                     }
    67                 }
    68             } catch (InterruptedException e) {
    69                 log.error(e.getMessage(), e);
    70             } catch (ExecutionException e) {
    71                 log.error(e.getMessage(), e);
    72             }
    73         }
    74     }
    75 
    76 }
     1 import lombok.extern.slf4j.Slf4j;
     2 import org.springframework.beans.factory.annotation.Autowired;
     3 import org.springframework.scheduling.annotation.Async;
     4 import org.springframework.scheduling.annotation.AsyncResult;
     5 import org.springframework.stereotype.Service;
     6 
     7 import javax.annotation.Resource;
     8 import java.util.concurrent.*;
     9 
    10 @Service
    11 @Slf4j
    12 public class CouponPresentLogServiceImpl implements CouponPresentLogService {
    13 
    14     @Autowired
    15     private CouponPresentLogDao couponPresentLogDao;
    16     @Resource
    17     private CouponSendRpcService couponSendRpcService;
    18 
    19     @Async("myThreadPoolTaskExecutor")
    20     @Override
    21     public Future<CouponPresentLogEntity> present(CouponPresentLogEntity entity) {
    22         try {
    23             CouponBaseResponse rst = couponSendRpcService.send(entity.getUserId(), entity.getCouponBatchKey(), "1", entity.getVendorId());
    24             if (null != rst && rst.isSuccess()) {
    25                 entity.setStatus(PresentStatusEnum.SUCCESS.getType());
    26                 entity.setFailureReason(PresentStatusEnum.SUCCESS.getName());
    27             }else {
    28                 String reason = (null == rst) ? "响应异常" : rst.getMsg();
    29                 entity.setFailureReason(reason);
    30                 entity.setStatus(PresentStatusEnum.FAILURE.getType());
    31             }
    32         }catch (Exception ex) {
    33             log.error(ex.getMessage(), ex);
    34             entity.setFailureReason(ex.getMessage());
    35             entity.setStatus(PresentStatusEnum.FAILURE.getType());
    36         }
    37         couponPresentLogDao.update(entity);
    38 
    39         return new AsyncResult<CouponPresentLogEntity>(entity);
    40     }
    41 
    42 }

     5、统计异步任务执行的进度

    利用Future获取执行结果,比如上面的例子中,由于不是直接提交的任务,所以用AsyncResult来返回结果

    上面的例子中,一个大任务,然后下面有许多子任务。在主任务中,统计各子任务的执行情况,是成功还是失败,然后统计成功多少,失败多少

    也可以这样写:

    @Autowired
    ThreadPoolTaskExecutor taskExecutor;
    
    Future<Object> future = taskExecutor.submit(new Callable<Object>() {
        @Override
        public Object call() throws Exception {
            return null;
        }
    });
     
  • 相关阅读:
    难以实践敏捷:估算
    使用AsyncEnumerator简化异步操作
    ESXi 入门配置
    学习模式,不如先了解问题
    我应该用哪种虚拟机?(一)
    在2003上实现Custom Task Pane
    我应该用哪种虚拟机?(终)
    我应该用哪种虚拟机?(二)
    正则表达式周二挑战赛 第十二周
    [译]Node中的ES6特性
  • 原文地址:https://www.cnblogs.com/cjsblog/p/9021398.html
Copyright © 2011-2022 走看看