一、订阅者
1、继承ApplicationEvent类,并可以添加自己所需要的参数
import org.springframework.context.ApplicationEvent;
public class BaseEvent extends ApplicationEvent {
public String requestJson = null;
public String bitNo = null;
public BaseEvent() {
super(new Object());
}
public BaseEvent(String bitNo, String requestJson) {
super(new Object());
this.requestJson = requestJson;
this.bitNo = bitNo;
if(EmptyUtil.isEmpty(this.bitNo)){
this.bitNo = UuidUtil.getUUID();
}
}
public String getRequestJson() {
return requestJson;
}
public void setRequestJson(String requestJson) {
this.requestJson = requestJson;
}
public String getBitNo() {
return bitNo;
}
public void setBizNo(String bitNo) {
this.bitNo = bitNo;
}
}
2、实现ApplicationEventPublisherAware接口
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
@Component
public class BasePublishAware implements ApplicationEventPublisherAware {
private static ApplicationEventPublisher applicationEventPublisher;
public static void publishEvent(BaseEvent event) {
applicationEventPublisher.publishEvent(event);
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}
3、创建DemoEvent继承BaseEvent
public class DemoEvent extends BaseEvent{
public DemoEvent() {
super();
}
public DemoEvent(String bizNo, String requestJson) {
super(bizNo, requestJson);
}
}
二、发布者
1、创建Listener并开启异步处理(用注解@EventListener方式)
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class DemoListener {
@Async
@EventListener
public void doSomeThing(DemoEvent event) {
System.out.println("DemoListener start ....");
System.out.println("DemoListener end ....");
}
}
【注】若@Async失效,可以在启动类加上@EnableAsync(proxyTargetClass=true)注解
三、编写测试类
public void event() {
System.out.println("DemoEvent start ....");
DemoEvent event = new DemoEvent(this, "DemoEvent");
BasePublishAware.publishEvent(event); // DemoEventListener 监听后处理
System.out.println("DemoEvent end ....");
}
四、输出结果
DemoEvent start ....
DemoEvent end ....
DemoListener start ....
DemoListener end ....
五、如果需要用日志记录Listener执行之后的结果(成功/失败)以便可以将失败的数据重新执行,则可以用抽象函数的方式将保存日志的函数写好,而每一个子类只专注于要实现的方法(这时候不能用注解方式,而要用implements ApplicationListener的方式)
0、导入Sql
CREATE TABLE `event_task_history` (
`task_history_id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '异常任务ID',
`bizNo` VARCHAR(45) NOT NULL COMMENT '任务号' COLLATE 'utf8mb4_general_ci',
`event_class` VARCHAR(400) NULL DEFAULT NULL COMMENT '事件Class类' COLLATE 'utf8mb4_general_ci',
`request_json` VARCHAR(4000) NULL DEFAULT NULL COMMENT '请求报文ID' COLLATE 'utf8mb4_general_ci',
`result` VARCHAR(4) NULL DEFAULT NULL COMMENT 'S成功 F失败' COLLATE 'utf8mb4_general_ci',
`error_message` VARCHAR(400) NULL DEFAULT NULL COMMENT '错误信息' COLLATE 'utf8mb4_general_ci',
`error_stack` TEXT NULL DEFAULT NULL COMMENT '错误堆栈信息' COLLATE 'utf8mb4_general_ci',
`created_date` DATETIME NULL DEFAULT NULL COMMENT '创建日期',
PRIMARY KEY (`task_history_id`) USING BTREE
)
COMMENT='事件任务记录表 '
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
1、定义Listener要继承的抽象类BaseEventListener
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.framework.utils.ExceptionUtils;
@Component
public abstract class BaseEventListener<T extends BaseEvent> implements ApplicationListener<T> {
@Autowired
private EventTaskHistoryService eventTaskHistoryService;
protected abstract void doBiz(T event) throws Exception;
@Async
public void onApplicationEvent(T event) {
try {
doBiz(event);
handleSuccess(event);
} catch(Exception e) {
handleError(e, event);
}
}
/**
* 调用失败
* @param throwable
* @param event
*/
public void handleError(Throwable throwable,ApplicationEvent event) {
//重新生成
BaseEvent baseEvent = (BaseEvent)event;
if(EmptyUtil.isNotEmpty(baseEvent)){
EventTaskHistory model = new EventTaskHistory();
model.setBizNo(baseEvent.getBitNo());
model.setRequestJson(baseEvent.getRequestJson());
model.setEventClass(event.getClass().getName());
model.setCreatedDate(new Date());
if (EmptyUtil.isNotEmpty(throwable)) {
model.setErrorMessage(throwable.getMessage());
model.setErrorStack(ExceptionUtils.buildExceptionStackTrace(throwable));
}
model.setResult("F");
eventTaskHistoryService.save(model);
}
}
/**
* 调用成功
* @param event
*/
public void handleSuccess(ApplicationEvent event) {
//重新生成
BaseEvent baseEvent = (BaseEvent)event;
if(EmptyUtil.isNotEmpty(baseEvent)){
EventTaskHistory model = new EventTaskHistory();
model.setBizNo(baseEvent.getBitNo());
model.setRequestJson(baseEvent.getRequestJson());
model.setEventClass(event.getClass().getName());
model.setCreatedDate(new Date());
model.setResult("S");
eventTaskHistoryService.save(model);
}
}
}
2、Listener继承BaseEventListener,实现抽象方法doBiz
@Component
public class DemoListener extends BaseEventListener<DemoEvent>{
private static Logger logger = LogManager.getLogger(DemoListener.class);
@Override
protected void doBiz(DemoEvent event) throws Exception {
System.out.println("DemoListener start ....");
System.out.println("DemoListener end ....");
}
}
@Component
public class DemoListener2 extends BaseEventListener<DemoEvent2>{
private static Logger logger = LogManager.getLogger(DemoListener2.class);
@Override
protected void doBiz(DemoEvent2 event) throws Exception {
System.out.println("DemoListener2 start ....");
System.out.println("DemoListener2 end ....");
}
}
3、将失败的数据重新执行
public static boolean reExcuteEvent(String taskHistoryId){
EventTaskHistoryService eventTaskHistoryService = SpringContextUtil.getBean(EventTaskHistoryService.class);
EventTaskHistory eventTaskHistory = eventTaskHistoryService.getById(taskHistoryId);
if(EmptyUtil.isEmpty(eventTaskHistory)) {
return false;
}
String eventClass = eventTaskHistory.getEventClass();
Object eventObject;
try {
Class<?> cls = Class.forName(eventClass);
eventObject = cls.newInstance();
BeanUtils.setProperty(eventObject, "bizNo", eventTaskHistory.getBizNo());
BeanUtils.setProperty(eventObject, "requestJson", eventTaskHistory.getRequestJson());
EventPublishAwareUtil.publishEvent((BaseEvent)eventObject);
} catch (Exception e) {
logger.error("reExcuteEvent error:" + e.getMessage());
return false;
}
return true;
}