SpringBoot > 啓動異步事件監聽機制

Spring 監聽/觀察者 模式 (異步啓用)

eg業務場景: 用戶下單,訂單建立成功,須要發送郵件通知用戶,爲用戶的訂單建立行爲增長積分,短信通知等等(訂單主體,訂單商品附屬表信息,訂單發貨信息,訂單分期支付信息,訂單優惠信息,支付優惠信息)一系列的動做的處理。java

  1. 事件 Event

(發送郵件,建立訂單商品附屬表信息,訂單發貨信息,訂單分期支付信息,訂單優惠信息,支付優惠信息 等等)能夠理解爲事件;在關注的業務 如 【訂單的建立(事件源)】,建立訂單後須要【發送郵件通知(事件發佈)】(事件:須要發送郵件或是其餘業務) , 這些後續不影響訂單主流程的業務,能夠拆解到監聽業務處理。spring

  1. 監聽 Listener

事件發送後,須要通知的對象,告訴須要進行的下一步的操做。如 發郵件 。監聽到事件發送後,作具體的業務處理,調用發送郵件邏輯進行發送。異步

  1. 開啓異步配置 Config

配置方式有兩種: 註解 和 xml配置async

  • xml配置
<!--異步線程池能夠定義多個,若在使用註解 @Async 時沒有指定使用哪一個線程池,則使用默認的線程
	1. ‘id' : 線程的名稱的前綴 
	2. ‘pool-size':線程池的大小。支持範圍」min-max」和固定值(此時線程池core和max sizes相同) 
	3. ‘queue-capacity' :排隊隊列長度 
-->
<!-- 缺省的異步任務線程池 --> 
<task:annotation-driven executor="asyncExecutor" />
<task:executor id="asyncExecutor" pool-size="100-10000" queue-capacity="10" />

<!-- 處理email發送的線程池 -->
<task:executor id="emailExecutor" pool-size="15-1000" queue-capacity="5" keep-alive="5"/>
  • 註解 @EnableAsync 配置(配置類)
@Configuration
@EnableAsync
public class SpringConfig {
 
	/** Set the ThreadPoolExecutor's core pool size. */
	private int corePoolSize = 10;
	/** Set the ThreadPoolExecutor's maximum pool size. */
	private int maxPoolSize = 200;
	/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
	private int queueCapacity = 10;
 
	private String ThreadNamePrefix = "asyncExecutor-";
 
	@Bean
	public Executor asyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(corePoolSize);
		executor.setMaxPoolSize(maxPoolSize);
		executor.setQueueCapacity(queueCapacity);
		executor.setThreadNamePrefix(ThreadNamePrefix);
 
		// rejection-policy:當pool已經達到max size的時候,如何處理新任務
		// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();
		return executor;
	}
 
}
  • 使用 @Async 註解啓用異步線程處理

這個註解用於標註某個方法或某個類裏面的全部方法都是須要異步處理的。被註解的方法被調用的時候,會在新線程中執行,而調用它的方法會在原來的線程中執行。這樣能夠避免阻塞、以及保證任務的實時性。適用於處理log、發送郵件、短信……等。ide

/**
 * 異步建立兌換碼
 * @Title: TicektCodeListener
 * @Description: 
 */
@Component
public class TicektCodeListener {
	
	@Autowired
	private MkDiscountCardService mkDiscountCardService;
	
	//異步監聽器
	@Async
	@EventListener
	public void dualEven(TicketCodeEvent event){
		
		mkDiscountCardService.createCardCode(event.getDto());
	}
	
}

項目使用實例:

下面使用 一個優惠券的券碼建立業務,來舉例使用。Spring的監聽/觀察者 模式。this

步驟:.net

  • 定義事件

事件定義,用於監聽者獲取 事件的屬性,信息傳遞線程

/**
 * 兌換碼
 * @Title: TODO
 */
public class TicketCodeEvent {

	private static final long serialVersionUID = 1L;
	
	private MkDiscountCardDto dto;

	public TicketCodeEvent(String code,MkDiscountCardDto dto) {
		this.code = code;
		this.dto = dto;
	}

	private String code;

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public MkDiscountCardDto getDto() {
		return dto;
	}

	public void setDto(MkDiscountCardDto dto) {
		this.dto = dto;
	}
	
	
}
  • 定義監聽器

注意code

  1. @Componet ,加入bean管理 , 同時要注意spring的包是否有掃描到。
  2. @Async , 啓用異步線程處理
  3. @EventListener ,聲明這個事件監聽器,監聽事件爲: TicketCodeEvent
/**
 * 異步建立兌換碼
 * @Title: TicektCodeListener
 * @Description: 
 */
 
@Component
public class TicektCodeListener {
	
	@Autowired
	private MkDiscountCardService mkDiscountCardService;
	
	//異步監聽器
	@Async
	@EventListener
	public void dualEven(TicketCodeEvent event){

		mkDiscountCardService.createCardCode(event.getDto());
	}
	
}
  • 事件發佈
  1. 使用註解注入獲取上下文,這次沒有采用 接口實現的方式xml

  2. 注意點:調用上下文 context.publishEvent(Event e) 發佈事件

@Service
public class MkDiscountCardServiceImpl implements MkDiscountCardService/*,ApplicationContextAware*/{
    
    private static final  Logger logger = LoggerFactory.getLogger(MkDiscountCardServiceImpl.class);
    
	
    @Autowired
    private ApplicationContext context;//上下文,用於發佈事件
	
	@Override
	@Transactional
	public Long createDiscountCardAct(CreateMkDiscountCardDto dto) {
		
        /**..... 
		省略一堆邏輯
		....*/
		
        //使用 spring 觀察者模式 異步處理
		
        MkDiscountCardDto cardDto = BeanUtils.copyProps(entity, MkDiscountCardDto.class);
		
        TicketCodeEvent event = new TicketCodeEvent("",cardDto);//構建事件
        this.context.publishEvent(event); //發佈事件
        return id;
	}
相關文章
相關標籤/搜索