詳解Java事件編程的使用
Java事件編程
當(dāng)前在線網(wǎng)店很多,很涉及商品管理和銷售的問題,比如:
一,在商品庫存管理的商品增加時(shí),我們主要業(yè)務(wù)時(shí)編輯保持商品信息,
同時(shí)因商品增加而附帶有一些“非主要業(yè)務(wù)”,如:
1,應(yīng)商品的庫存數(shù)量等更新,
2,熱銷產(chǎn)品的推廣處理等
二,在商品產(chǎn)生訂單時(shí),我們的主要業(yè)務(wù)(對(duì)買家而言)是建立訂單業(yè)務(wù),
同時(shí)因產(chǎn)生訂單而附帶有一些不是買家關(guān)心的“非主要業(yè)務(wù)”,如:
1,庫存和已售數(shù)量的更新
2,發(fā)貨的準(zhǔn)備處理事宜
3,物流的處理事宜
非主要業(yè)務(wù)我們可以讓程序使用多線程異步執(zhí)行,這樣主要業(yè)務(wù)和非主要業(yè)務(wù)就完全解耦,
主要業(yè)務(wù)可以快速完成響應(yīng),非主要業(yè)務(wù)多線程異步執(zhí)行,提高程序的吞吐量即高處理能力;
同時(shí)使用自定義的線程池,有比較好的把控;
下面我們就根據(jù)上面的場景需求編寫一個(gè)例子,看看在Springboot中如何Java的事件編程,
對(duì)比一下常規(guī)邏輯的編程,和采用Java事件編程的差異。
//常規(guī)邏輯的編程
@GetMapping(value="/add")
@ResponseBody
public String addProduct(Product product) {
//增加產(chǎn)品
//應(yīng)商品的庫存數(shù)量等更新
//是否為熱銷產(chǎn)品的推廣處理
//其它處理
return "產(chǎn)品增加完成";
}
主要業(yè)務(wù)是增加產(chǎn)品信息,但是可能會(huì)因產(chǎn)品庫存或熱銷產(chǎn)品等其它問題處理而收到影響,
耦合性比較強(qiáng),如果以后還有其它需求又需要改動(dòng)程序,問題暴露出來了;
同樣,下單也是一樣問題,主要業(yè)務(wù)是買家下單時(shí)建立訂單,
//常規(guī)邏輯的編程
@GetMapping(value="/createOrder")
@ResponseBody
public String createProductOrder(ProductOrder productOrder) {
//收集產(chǎn)品訂單信息,保持建立訂單
//庫存和已售數(shù)量的更新
//訂單備貨處理
//物流處理
return "產(chǎn)品訂單建立完成";
}
對(duì)買家來說,主要業(yè)務(wù)是產(chǎn)品下單,后續(xù)的庫存和已售數(shù)量的更新,備貨處理,物流處理等不是買家關(guān)心的,但是可能會(huì)因這些問題處理而受到影響,可能下單失敗,耦合性比較強(qiáng),如果以后還有其它需求又需要改動(dòng)程序,同樣問題暴露出來了;
那怎么建立主次分明的處理邏輯呢,這里用Java事件編程就很好處理這些問題,主次分明,完全解耦,程序改動(dòng)比較小,程序吞吐量也強(qiáng),
相關(guān)注釋在程序非常清楚,所以主要看代碼吧;
三,使用Java事件編程,Springboot例子,
1,項(xiàng)目結(jié)構(gòu)如下圖:

2,自定義異步執(zhí)行使用的線程池,參考如下代碼:
package com.shenzhennba.pro06.eventSource.asyncConfig;
import java.io.Serializable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 配置異步任務(wù)線程池,然后注入springIOC容器,提供異步任務(wù)使用;
* @author shenzhenNBA
* @since 2021/06/14
*/
@Configuration
public class AsyncThreadPoolConfig implements Serializable {
private static final long serialVersionUID = 20210606010060L;
private static final int MAX_POOL_SIZE = 100;
private static final int CORE_POOL_SIZE = 20;
private static final String THREAD_NAME_PREFIX = "async_task_";
//創(chuàng)建線程池,并指定實(shí)例名稱
@Bean("asyncTaskExecutor")
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
asyncTaskExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);
asyncTaskExecutor.initialize();
return asyncTaskExecutor;
}
}
3,定義業(yè)務(wù)相關(guān)需要的實(shí)體或model,參考如下代碼:
package com.shenzhennba.pro06.eventSource.model;
import java.io.Serializable;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
/**
* 商品實(shí)體類
* @author shenzhenNBA
* @since 2021/06/14
*/
public class Product implements Serializable {
private static final long serialVersionUID = 20210606010010L;
private String categoryCode;//商品類別代碼
private String productName; //商品名稱
private String productCode; //商品代碼
private Double price; //商品單價(jià)
private Long addNum; //增加數(shù)量
private Long isHotSell=0L; //是否促銷,0=不是,1=是
private String createTime; //商品入庫時(shí)間
public Product() {
super();
}
//getter / setter 省略...
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
package com.shenzhennba.pro06.eventSource.model;
import java.io.Serializable;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
/**
* 商品的數(shù)量和積分相關(guān)實(shí)體類
* @author shenzhenNBA
* @since 2021/06/14
*/
public class ProductNumber implements Serializable {
private static final long serialVersionUID = 20210606010020L;
private String productCode; //商品代碼
private Long storageNum; //商品庫存
private Long soldNum; //已收數(shù)量
private Long scoreNum; //單個(gè)購買贈(zèng)送積分?jǐn)?shù)
public ProductNumber() {
super();
}
// getter / setter 省略...
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
package com.shenzhennba.pro06.eventSource.model;
import java.io.Serializable;
import java.util.Date;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
/**
* 商品訂單實(shí)體類
* @author shenzhenNBA
* @since 2021/06/14
*/
public class ProductOrder implements Serializable {
private static final long serialVersionUID = 20210606010030L;
private String orderCode; //訂單代碼
private String productName; //商品名稱
private String productCode; //商品代碼
private Double price; //商品單價(jià)
private String createTime; //下單時(shí)間
private Long scoreNum; //購買贈(zèng)送積分?jǐn)?shù)
private Long buyNum; //訂單購買數(shù)量
private Integer isPrepared = 0;//發(fā)貨準(zhǔn)備狀態(tài),默認(rèn)0=未準(zhǔn)備好,1=已準(zhǔn)備好
private Integer isSendOut = 0;//是否已發(fā)貨,默認(rèn)0=未發(fā),1=已發(fā)
private String warehouseCode ;//發(fā)貨倉庫代碼
private String senderCode ; //物流處理商家代碼
private Date planSendTime ; //計(jì)劃發(fā)貨時(shí)間
private Date recieveTime ; //收貨時(shí)間
private String recieveAddress;//收貨地址
public ProductOrder() {
super();
}
// getter / setter 省略...
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
4,定義業(yè)務(wù)的相關(guān)Java事件源,主要是編寫繼承
org.springframework.context.ApplicationEvent 的類對(duì)象,
以及定義各事件相關(guān)的對(duì)象,比如,商品對(duì)象,或訂單對(duì)象,事件源的目的是存儲(chǔ)事件相關(guān)的目標(biāo)信息,參考如下代碼:
package com.shenzhennba.pro06.eventSource.eventSource;
import java.io.Serializable;
import org.springframework.context.ApplicationEvent;
import com.shenzhennba.pro06.eventSource.model.Product;
/**
* 商品添加事件源的定義,目的是用于存儲(chǔ)事件的目標(biāo)信息,即添加的商品對(duì)象;
* 注意:是繼承ApplicationEvent的普通Bean對(duì)象
* @author shenzhenNBA
* @since 2021/06/14
*/
public class ProductEventSource
extends ApplicationEvent implements Serializable {
private static final long serialVersionUID = 20210606010040L;
//目的是用于存儲(chǔ)事件的目標(biāo)信息,即添加的商品對(duì)象
private Product product;
public ProductEventSource(Product source) {
super(source);
this.product = source;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
package com.shenzhennba.pro06.eventSource.eventSource;
import java.io.Serializable;
import org.springframework.context.ApplicationEvent;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;
/**
* 商品訂單建立事件源的定義,目的是用于存儲(chǔ)事件的目標(biāo)信息,即建立的商品訂單對(duì)象;
* 注意:是繼承ApplicationEvent的普通Bean對(duì)象
* @author shenzhenNBA
* @since 2021/06/14
*/
public class ProductOrderEventSource
extends ApplicationEvent implements Serializable{
private static final long serialVersionUID = 20210606010050L;
//目的是用于存儲(chǔ)事件的目標(biāo)信息,即建立的商品訂單對(duì)象
private ProductOrder productOrder;
public ProductOrderEventSource(ProductOrder source) {
super(source);
this.productOrder = source;
}
public ProductOrder getProductOrder() {
return productOrder;
}
public void setProductOrder(ProductOrder productOrder) {
this.productOrder = productOrder;
}
}
5,定義各種監(jiān)聽器和相關(guān)業(yè)務(wù)處理邏輯,并將其納入SpringIOC容器管理,
監(jiān)聽類方法加注解 @EventListener 使之變?yōu)橐粋€(gè)監(jiān)聽器,加注解@Async("asyncTaskExecutor") 指定監(jiān)聽器異步執(zhí)行,同時(shí)指定異步執(zhí)行使用的線程池,加注解 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
指定監(jiān)聽器事務(wù)的階段, 一般為業(yè)務(wù)數(shù)據(jù)入庫之后,再異步執(zhí)行方法;加注解 @Order(1) 指定同一事件有多個(gè)監(jiān)聽器時(shí)執(zhí)行順序,值越小,執(zhí)行順序優(yōu)先,類前加 @Component 注解,把各監(jiān)聽器交給SpringIOC容器管理,參考如下代碼:
package com.shenzhennba.pro06.eventSource.listener;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import com.shenzhennba.pro06.eventSource.eventSource.ProductEventSource;
import com.shenzhennba.pro06.eventSource.eventSource.ProductOrderEventSource;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;
/**
* 定義各種事件監(jiān)聽器和其各自的業(yè)務(wù)處理邏輯,
* 然后注入springIOC容器,并監(jiān)聽相應(yīng)的事件,只要觸發(fā)相應(yīng)事件則用對(duì)應(yīng)監(jiān)聽器處理;
* 注意:各種監(jiān)聽器還是由spring容器管理
* @author shenzhenNBA
* @since 2021/06/14
*/
@Component
public class EventListeners implements Serializable {
private static Logger logger = LoggerFactory.getLogger(EventListeners.class);
private static final long serialVersionUID = 20210606010070L;
//指定異步執(zhí)行監(jiān)聽器,同時(shí)使用的自定義的異步線程池
@Async("asyncTaskExecutor")
//指定監(jiān)聽事務(wù)的階段,多數(shù)情況下的業(yè)務(wù)操作會(huì)涉及數(shù)據(jù)庫事務(wù),確保主業(yè)務(wù)的數(shù)據(jù)入庫后,再進(jìn)行本方法的異步操作
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
//注解定義本方法為一個(gè)監(jiān)聽器,處理因增加產(chǎn)品而引發(fā)的事件中有關(guān)產(chǎn)品庫存等數(shù)量相關(guān)信息
@EventListener
//指定當(dāng)同一個(gè)事件有多個(gè)監(jiān)聽器時(shí)執(zhí)行順序,值越小,執(zhí)行順序優(yōu)先
@Order(1)
public void updateProductReferNumListener(ProductEventSource pes) {
if (null == pes || null == pes.getProduct()) {
return;
}
logger.info("");
logger.info("產(chǎn)品增加事件監(jiān)聽器 1, 事件關(guān)聯(lián)信息:{}", pes.getProduct());
logger.info("");
// TODO 有關(guān)產(chǎn)品數(shù)量的庫存等更新操作
}
//指定異步執(zhí)行監(jiān)聽器,同時(shí)使用的自定義的異步線程池
@Async("asyncTaskExecutor")
//指定監(jiān)聽事務(wù)的階段,多數(shù)情況下的業(yè)務(wù)操作會(huì)涉及數(shù)據(jù)庫事務(wù),確保主業(yè)務(wù)的數(shù)據(jù)入庫后,再進(jìn)行本方法的異步操作
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
//注解定義本方法為一個(gè)監(jiān)聽器,處理因增加產(chǎn)品而引發(fā)的事件中有關(guān)熱銷產(chǎn)品的相關(guān)促銷事宜
@EventListener
//指定當(dāng)同一個(gè)事件有多個(gè)監(jiān)聽器時(shí)執(zhí)行順序,值越小,執(zhí)行順序優(yōu)先
@Order(5)
public void handleHotSellProductListener(ProductEventSource pes) {
if (null == pes || null == pes.getProduct()) {
return;
}
logger.info("");
logger.info("產(chǎn)品增加事件監(jiān)聽器 2, 事件關(guān)聯(lián)信息:{}", pes.getProduct());
logger.info("");
if (null == pes.getProduct()) {
return;
}
if (1 != pes.getProduct().getIsHotSell().intValue()) {
logger.info("產(chǎn)品增加事件監(jiān)聽器 2, 非熱銷產(chǎn)品");
return;
}
// TODO 有關(guān)熱銷產(chǎn)品的相關(guān)促銷事宜的處理
}
//指定異步執(zhí)行監(jiān)聽器,同時(shí)使用的自定義的異步線程池
@Async("asyncTaskExecutor")
//指定監(jiān)聽事務(wù)的階段,多數(shù)情況下的業(yè)務(wù)操作會(huì)涉及數(shù)據(jù)庫事務(wù),確保主業(yè)務(wù)的數(shù)據(jù)入庫后,再進(jìn)行本方法的異步操作
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
//注解定義本方法為一個(gè)監(jiān)聽器,處理因產(chǎn)品產(chǎn)生訂單而引發(fā)的事件中有關(guān)產(chǎn)品庫存和已售數(shù)量相關(guān)信息
@EventListener
//指定當(dāng)同一個(gè)事件有多個(gè)監(jiān)聽器時(shí)執(zhí)行順序,值越小,執(zhí)行順序優(yōu)先
@Order(1)
public void updateProductReferNumListener(ProductOrderEventSource poes) {
if (null == poes || null == poes.getProductOrder()) {
return;
}
logger.info("");
logger.info("產(chǎn)品產(chǎn)生訂單事件監(jiān)聽器 1, 事件關(guān)聯(lián)信息:{}", poes.getProductOrder());
logger.info("");
// TODO 有關(guān)產(chǎn)品數(shù)量的庫存和已售數(shù)量更新操作
}
//指定異步執(zhí)行監(jiān)聽器,同時(shí)使用的自定義的異步線程池
@Async("asyncTaskExecutor")
//指定監(jiān)聽事務(wù)的階段,多數(shù)情況下的業(yè)務(wù)操作會(huì)涉及數(shù)據(jù)庫事務(wù),確保主業(yè)務(wù)的數(shù)據(jù)入庫后,再進(jìn)行本方法的異步操作
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
//注解定義本方法為一個(gè)監(jiān)聽器,處理因產(chǎn)品產(chǎn)生訂單而引發(fā)的事件中有關(guān)產(chǎn)品發(fā)貨的相關(guān)準(zhǔn)備和處理事宜
@EventListener
//指定當(dāng)同一個(gè)事件有多個(gè)監(jiān)聽器時(shí)執(zhí)行順序,值越小,執(zhí)行順序優(yōu)先
@Order(5)
public void prepareSendProductListener(ProductOrderEventSource poes) {
if (null == poes || null == poes.getProductOrder()) {
return;
}
ProductOrder proOrder = poes.getProductOrder();
logger.info("");
logger.info("產(chǎn)品產(chǎn)生訂單事件監(jiān)聽器 2, 事件關(guān)聯(lián)信息:{}", proOrder);
logger.info("");
if (null != proOrder.getIsSendOut() &&
1 == proOrder.getIsSendOut()) {
logger.info("產(chǎn)品產(chǎn)生訂單事件監(jiān)聽器 2, 訂單已經(jīng)發(fā)貨,不用再處理");
return;
}
if (null != proOrder.getIsPrepared() &&
1 == proOrder.getIsPrepared()) {
logger.info("產(chǎn)品產(chǎn)生訂單事件監(jiān)聽器 2, 訂單發(fā)貨準(zhǔn)備已經(jīng)完成,不用再處理");
return;
}
// TODO 有關(guān)產(chǎn)品訂單發(fā)貨的事宜
}
//指定異步執(zhí)行監(jiān)聽器,同時(shí)使用的自定義的異步線程池
@Async("asyncTaskExecutor")
//指定監(jiān)聽事務(wù)的階段,多數(shù)情況下的業(yè)務(wù)操作會(huì)涉及數(shù)據(jù)庫事務(wù),確保主業(yè)務(wù)的數(shù)據(jù)入庫后,再進(jìn)行本方法的異步操作
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
//注解定義本方法為一個(gè)監(jiān)聽器,處理因產(chǎn)品產(chǎn)生訂單而引發(fā)的事件中有關(guān)產(chǎn)品發(fā)貨的物流事宜
@EventListener
//指定當(dāng)同一個(gè)事件有多個(gè)監(jiān)聽器時(shí)執(zhí)行順序,值越小,執(zhí)行順序優(yōu)先
@Order(10)
public void sendProductListener(ProductOrderEventSource poes) {
if (null == poes || null == poes.getProductOrder()) {
return;
}
ProductOrder proOrder = poes.getProductOrder();
logger.info("");
logger.info("產(chǎn)品產(chǎn)生訂單事件監(jiān)聽器 3, 事件關(guān)聯(lián)信息:{}", poes.getProductOrder());
logger.info("");
if (null != proOrder.getIsSendOut() &&
1 == proOrder.getIsSendOut()) {
logger.info("產(chǎn)品產(chǎn)生訂單事件監(jiān)聽器 3, 訂單已經(jīng)發(fā)貨,不用再處理");
return;
}
if (null != proOrder.getIsPrepared() &&
0 == proOrder.getIsPrepared().intValue()) {
logger.info("產(chǎn)品產(chǎn)生訂單事件監(jiān)聽器 3, 訂單發(fā)貨準(zhǔn)備還未完成,先等備好貨,再處理物流事宜");
}
// TODO 有關(guān)產(chǎn)品訂單的物流事宜
}
}
6,定義業(yè)務(wù)接口,參考如下代碼:
package com.shenzhennba.pro06.eventSource.service;
import java.io.Serializable;
import com.shenzhennba.pro06.eventSource.model.Product;
/**
* 商品service層接口
* @author shenzhenNBA
* @since 2021/06/14
*/
public interface ProductService extends Serializable {
/**
* 增加產(chǎn)品
* @author shenzhenNBA
* @param product
* @return
*/
Integer addProduct(Product product);
/**
* 根據(jù)產(chǎn)品代碼查詢產(chǎn)品記錄
* @author shenzhenNBA
* @param product
* @return
*/
Product getProduct(String productCode);
}
package com.shenzhennba.pro06.eventSource.service;
import java.io.Serializable;
import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;
/**
* 商品訂單service層接口
* @author shenzhenNBA
* @since 2021/06/14
*/
public interface ProductOrderService extends Serializable {
/**
* 建立產(chǎn)品訂單
* @author shenzhenNBA
* @param product
* @return
*/
Integer createProductOrder(ProductOrder productOrder);
/**
* 根據(jù)產(chǎn)品訂單代碼查詢產(chǎn)品訂單記錄
* @author shenzhenNBA
* @param product
* @return
*/
Product getProductOrder(String productOrderCode);
}
7,實(shí)現(xiàn)所定義的業(yè)務(wù)接口,參考如下代碼:
package com.shenzhennba.pro06.eventSource.service.impl;
import org.springframework.stereotype.Service;
import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.service.ProductService;
/**
* 商品service接口實(shí)現(xiàn)類
* @author shenzhenNBA
* @since 2021/06/14
*/
@Service
public class ProductServiceImpl implements ProductService {
private static final long serialVersionUID = 20210606010090L;
/**
* 增加產(chǎn)品
*/
@Override
public Integer addProduct(Product product) {
// TODO more biz handle here
return null;
}
/**
* 根據(jù)產(chǎn)品代碼查詢產(chǎn)品記錄
*/
@Override
public Product getProduct(String productCode) {
// TODO more biz handle here
return null;
}
}
package com.shenzhennba.pro06.eventSource.service.impl;
import org.springframework.stereotype.Service;
import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;
import com.shenzhennba.pro06.eventSource.service.ProductOrderService;
/**
* 商品訂單service接口實(shí)現(xiàn)類
* @author shenzhenNBA
* @since 2021/06/14
*/
@Service
public class ProductOrderServiceImpl implements ProductOrderService {
private static final long serialVersionUID = 20210606010100L;
/**
* 建立產(chǎn)品訂單
*/
@Override
public Integer createProductOrder(ProductOrder productOrder) {
// TODO more biz handle here
return null;
}
/**
* 根據(jù)產(chǎn)品訂單代碼查詢產(chǎn)品訂單記錄
*/
@Override
public Product getProductOrder(String productOrderCode) {
// TODO more biz handle here
return null;
}
}
8,在對(duì)外API(即controller層)接口中處理業(yè)務(wù),同時(shí)使用 org.springframework.context.ApplicationEventPublisher
實(shí)例發(fā)布相應(yīng)的Java事件,參考如下代碼:
package com.shenzhennba.pro06.eventSource.controller;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.shenzhennba.pro06.eventSource.eventSource.ProductEventSource;
import com.shenzhennba.pro06.eventSource.listener.EventListeners;
import com.shenzhennba.pro06.eventSource.model.Product;
import com.shenzhennba.pro06.eventSource.service.ProductService;
/**
* 使用Java事件編程方式實(shí)現(xiàn),
* 產(chǎn)品對(duì)外API接口,
* @author shenzhenNBA
* @since 2021/06/14
*/
@Controller
@RequestMapping("/product")
public class ProductController implements Serializable {
private static Logger logger = LoggerFactory.getLogger(EventListeners.class);
private static final long serialVersionUID = 20210606010080L;
//Spring的事件發(fā)布器
@Autowired
private ApplicationEventPublisher appEventPublisher;
@Autowired
private ProductService productService;
@GetMapping(value="/add")
@ResponseBody
public String addProduct(Product product) {
logger.info("controller ProductController.addProduct(), add product");
//主要業(yè)務(wù),增加產(chǎn)品
productService.addProduct(product);
//?categoryCode=c01&productName=productName001&productCode=pc001&price=20.5&addNum=2&isHotSell=1
//因增加產(chǎn)品而發(fā)布與其相關(guān)的事件,處理與之相關(guān)的非主要業(yè)務(wù),
//首先執(zhí)行EventListeners.updateProductReferNumListener()監(jiān)聽器,處理相關(guān)業(yè)務(wù)
//其次執(zhí)行EventListeners.handleHotSellProductListener()監(jiān)聽器,處理相關(guān)業(yè)務(wù)
//應(yīng)用Spring事件,可以讓非主要業(yè)務(wù)和主要業(yè)務(wù)解耦,使用異步處理非主要業(yè)務(wù),讓程序吞吐量即處理能力更強(qiáng)
appEventPublisher.publishEvent(new ProductEventSource(product));
return "產(chǎn)品增加完成";
}
}
package com.shenzhennba.pro06.eventSource.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.shenzhennba.pro06.eventSource.eventSource.ProductOrderEventSource;
import com.shenzhennba.pro06.eventSource.listener.EventListeners;
import com.shenzhennba.pro06.eventSource.model.ProductOrder;
import com.shenzhennba.pro06.eventSource.service.ProductOrderService;
/**
* 使用Java事件編程方式實(shí)現(xiàn),
* 產(chǎn)品訂單對(duì)外API接口,
* @author shenzhenNBA
* @since 2021/06/14
*/
@Controller
@RequestMapping("/productOrder")
public class ProductOrderController {
private static Logger logger = LoggerFactory.getLogger(EventListeners.class);
private static final long serialVersionUID = 20210606010080L;
//Spring的事件發(fā)布器
@Autowired
private ApplicationEventPublisher appEventPublisher;
@Autowired
private ProductOrderService productOrderService;
@GetMapping(value="/createOrder")
@ResponseBody
public String createProductOrder(ProductOrder productOrder) {
logger.info("controller ProductOrderController.createProductOrder(), create product order");
//主要業(yè)務(wù),增加產(chǎn)品
productOrderService.createProductOrder(productOrder);
//?productCode=pc001&productName=productName001&price=20.5&buyNum=3&
//scoreNum=0&warehouseCode=house01&recieveAddress=add001
//因增加產(chǎn)品而發(fā)布與其相關(guān)的事件,處理與之相關(guān)的非主要業(yè)務(wù),
//首先執(zhí)行EventListeners.updateProductReferNumListener()監(jiān)聽器,處理相關(guān)業(yè)務(wù)
//其次執(zhí)行EventListeners.prepareSendProductListener()監(jiān)聽器,處理相關(guān)業(yè)務(wù)
//再次執(zhí)行EventListeners.sendProductListener()監(jiān)聽器,處理相關(guān)業(yè)務(wù)
//應(yīng)用Spring事件,可以讓非主要業(yè)務(wù)和主要業(yè)務(wù)解耦,使用異步處理非主要業(yè)務(wù),讓程序吞吐量即處理能力更強(qiáng)
appEventPublisher.publishEvent(new ProductOrderEventSource(productOrder));
return "產(chǎn)品訂單建立完成";
}
}
9,在啟動(dòng)類中啟用異步處理功能,參考如下代碼:
package com.shenzhennba.pro06.eventSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.scheduling.annotation.EnableAsync;
//啟動(dòng)異步處理功能
@EnableAsync
//啟動(dòng)springboot但不用排除DB功能
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class EventSourceApp {
private static Logger logger = LoggerFactory.getLogger(EventSourceApp.class);
public static void main(String[] args) {
SpringApplication.run(EventSourceApp.class, args);
logger.info("");
logger.info("----------- Server is running... -----------");
logger.info("");
}
}
10,工程配置文件,參考如下代碼:
spring.application.name=eventSourceApp01 server.port=8080
11,啟動(dòng)工程,模擬增加一個(gè)商品,相關(guān)截圖如下,可見商品增加事件已經(jīng)觸發(fā),
http://localhost:8080/product/add?categoryCode=c01&productName=productName001&productCode=pc001&price=20.5&addNum=2&isHotSell=1


12,啟動(dòng)工程,模擬建立一個(gè)訂單,相關(guān)截圖如下,可見訂單相關(guān)事件已經(jīng)觸發(fā),
http://localhost:8080/productOrder/createOrder?productCode=pc001&productName=productName001&price=20.5&buyNum=3&scoreNum=0&wa
rehouseCode=house01&recieveAddress=add001


13,工程 pom.xml 文件,參見如下代碼:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.shenzhennba.pro06</groupId> <artifactId>eventSource</artifactId> <version>0.0.1-SNAPSHOT</version> <name>eventSource</name> <description>Demo event source</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- apache的依賴 --> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
后記
Java的事件編程可以應(yīng)用到很多的地方,合理應(yīng)用可以使代碼主次業(yè)務(wù)分清,業(yè)務(wù)解耦,提高程序吞吐量,但需要開發(fā)人員掌握更多的知識(shí),只要學(xué)習(xí)應(yīng)該不是很難,習(xí)慣一種編程邏輯多一種開發(fā)思路,歡迎拍磚討論...
到此這篇關(guān)于詳解Java事件編程的使用的文章就介紹到這了,更多相關(guān)Java事件編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中對(duì)null進(jìn)行強(qiáng)制類型轉(zhuǎn)換的方法
小編對(duì)null進(jìn)行強(qiáng)轉(zhuǎn)會(huì)不會(huì)拋錯(cuò),非常的好奇,下面小編通過實(shí)例代碼給大家介紹Java中對(duì)null進(jìn)行強(qiáng)制類型轉(zhuǎn)換的方法,感興趣的朋友參考下吧2018-09-09
java高效打印一個(gè)二維數(shù)組的實(shí)例(不用遞歸,不用兩個(gè)for循環(huán))
下面小編就為大家?guī)硪黄猨ava高效打印一個(gè)二維數(shù)組的實(shí)例(不用遞歸,不用兩個(gè)for循環(huán))。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03
java編程無向圖結(jié)構(gòu)的存儲(chǔ)及DFS操作代碼詳解
這篇文章主要介紹了java編程無向圖結(jié)構(gòu)的存儲(chǔ)及DFS操作代碼詳解,具有一定借鑒價(jià)值,需要的朋友可以了解下。2017-12-12
Java基礎(chǔ)知識(shí)之成員變量和局部變量淺顯易懂總結(jié)
從語法形式上,看成員變量是屬于類的,而局部變量是在方法中定義的變量或是方法的參數(shù);成員變量可以被public,private,static等修飾符所修飾,而局部變量不能被訪問控制修飾符及static所修飾2021-09-09
springboot配置http跳轉(zhuǎn)https的過程
SSL是為網(wǎng)絡(luò)通信提供安全以及保證數(shù)據(jù)完整性的的一種安全協(xié)議,SSL在網(wǎng)絡(luò)傳輸層對(duì)網(wǎng)絡(luò)連接進(jìn)行加密,這篇文章主要介紹了springboot配置http跳轉(zhuǎn)https的過程,需要的朋友可以參考下2023-04-04
Java中BufferedReader與BufferedWriter類的使用示例
BufferedReader與BufferedWriter分別繼承于Reader和Writer類,分別為字符的讀取和寫入添加緩沖功能,這里我們就來看一下Java中BufferedReader與BufferedWriter類的使用示例:2016-06-06
Java高級(jí)特性之反射機(jī)制實(shí)例詳解
這篇文章主要介紹了Java高級(jí)特性之反射機(jī)制,結(jié)合實(shí)例形式詳細(xì)分析了Java反射機(jī)制原理、功能、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2018-08-08

