JAVA发布订阅模式Demo,支持异步+记录日志+重新发布操作

一、订阅者
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;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值