eg业务场景: 用户下单,订单建立成功,须要发送邮件通知用户,为用户的订单建立行为增长积分,短信通知等等(订单主体,订单商品附属表信息,订单发货信息,订单分期支付信息,订单优惠信息,支付优惠信息)一系列的动做的处理。java
(发送邮件,建立订单商品附属表信息,订单发货信息,订单分期支付信息,订单优惠信息,支付优惠信息 等等)能够理解为事件;在关注的业务 如 【订单的建立(事件源)】,建立订单后须要【发送邮件通知(事件发布)】(事件:须要发送邮件或是其余业务) , 这些后续不影响订单主流程的业务,能够拆解到监听业务处理。spring
事件发送后,须要通知的对象,告诉须要进行的下一步的操做。如 发邮件 。监听到事件发送后,作具体的业务处理,调用发送邮件逻辑进行发送。异步
配置方式有两种: 注解 和 xml配置async
<!--异步线程池能够定义多个,若在使用注解 @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"/>
@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; } }
这个注解用于标注某个方法或某个类里面的全部方法都是须要异步处理的。被注解的方法被调用的时候,会在新线程中执行,而调用它的方法会在原来的线程中执行。这样能够避免阻塞、以及保证任务的实时性。适用于处理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
/** * 异步建立兑换码 * @Title: TicektCodeListener * @Description: */ @Component public class TicektCodeListener { @Autowired private MkDiscountCardService mkDiscountCardService; //异步监听器 @Async @EventListener public void dualEven(TicketCodeEvent event){ mkDiscountCardService.createCardCode(event.getDto()); } }
使用注解注入获取上下文,这次没有采用 接口实现的方式xml
注意点:调用上下文 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; }