使用spring的事件机制做回调
原代码
事件类
package com.cvte.maxhub.mhqa.event;
import lombok.Data;
@Data
public class QueueBuildCompletedEvent<T> {
private T data;
}
监听器类
package com.cvte.maxhub.mhqa.listener;
import com.cvte.maxhub.mhqa.event.QueueBuildCompletedEvent;
public interface QueueBuildCompletedEventListener<T> {
void onQueueBuildCompletedEvent(QueueBuildCompletedEvent<T> event);
}
发送事件端
package com.cvte.maxhub.mhqa.link.controller;
import com.cvte.maxhub.mhqa.event.QueueBuildCompletedEvent;
import com.cvte.maxhub.mhqa.link.domain.QueueBuildDO;
import com.cvte.maxhub.mhqa.link.domain.request.VesselQueueBuildCreatingRequest;
import com.cvte.maxhub.mhqa.link.service.QueueBuildService;
import com.cvte.maxhub.mhqa.support.Result;
import com.cvte.maxhub.mhqa.support.ResultBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/link/jobs/queue")
@RequiredArgsConstructor
@Slf4j
public class QueueBuildController {
private final QueueBuildService<QueueBuildDO> queueBuildService;
private final ApplicationEventPublisher publisher;
@PostMapping
public Result addForVessel(@RequestBody @Validated VesselQueueBuildCreatingRequest request) {
queueBuildService.addForVessel(request);
return ResultBuilder.success(null);
}
@GetMapping("test")
public Result test() {
QueueBuildCompletedEvent<String> testEvent = new QueueBuildCompletedEvent<>();
testEvent.setData("");
publisher.publishEvent(testEvent);
log.error("请求发出去了");
return ResultBuilder.success();
}
}
处理事件端
package com.cvte.maxhub.mhqa.link.service.impl;
/**
* @author zhongxie
*/
@Service
@RequiredArgsConstructor
@Slf4j
@EnableScheduling
public class QueueBuildServiceImpl implements QueueBuildCompletedEventListener<String> {
private static final String COLUMN_NAME_STATUS = "c_status";
private static final String COLUMN_NAME_UUID = "c_uuid";
private static final String COLUMN_NAME_CREATE_TIME = "c_create_time";
private static final String COLUMN_NAME_DEVICE_CHANNEL = "c_device_channel";
private static final String COLUMN_NAME_BUILD_UUID = "c_build_uuid";
@Async
@EventListener()
@Override
public void onQueueBuildCompletedEvent(QueueBuildCompletedEvent<String> event) {
log.error("我接收到事件了:{}", event);
String buildUuid = event.getData();
if (!StringUtils.isEmpty(buildUuid)) {
UpdateWrapper<QueueBuildDO> wrapper = new UpdateWrapper<QueueBuildDO>()
.eq(COLUMN_NAME_BUILD_UUID, buildUuid)
.eq(COLUMN_NAME_STATUS, QueueBuildStatusEnum.RUNNING)
.set(COLUMN_NAME_STATUS, QueueBuildStatusEnum.FINISH);
update(wrapper);
}
}
}
异常现象
发送事件后,事件接收端无法正常接收到事件并处理。
觉得很神奇,猜测事件机制不支持泛型导致? --> 不太可能,作为spring的一个机制,不应该这么不成熟
应该是没有开启支持泛型消息导致的
查野生文档
说了很多消息机制的实现原理,但是没解决我的问题,隐隐感觉与类型转换又关系
blog.csdn.net/ITlikeyou/a…
blog.csdn.net/yyb_gz/arti…
查找官方文档@EventListner的说明
docs.spring.io/spring-fram…
寻找关键词@EventListener
有以下两段描述:
第一个方案描述
大概意思是@EventListener中指定需要监听的event类型,并在形参中明确的泛型的实际类型可以进一步缩小事件的范围
可以在@EventListener()的value中签名需要监听的事件类型,形参中便可使用泛型了
第二个方案描述
大概意思是由于类型擦出的存在,泛型事件类型可以通过继承ApplicationEvent并实现ResolvableTypeProvider来获得更好的特性支持
以泛型的实际类型为String类型为例,试验以上两种方法
根据方案一修改后
能正常获取事件。
@Async
@EventListener({QueueBuildCompletedEvent.class})
@Override
public void onQueueBuildCompletedEvent(QueueBuildCompletedEvent<String> event) {
log.error("我接收到事件了:{}", event);
String buildUuid = event.getData();
if (!StringUtils.isEmpty(buildUuid)) {
UpdateWrapper<QueueBuildDO> wrapper = new UpdateWrapper<QueueBuildDO>()
.eq(COLUMN_NAME_BUILD_UUID, buildUuid)
.eq(COLUMN_NAME_STATUS, QueueBuildStatusEnum.RUNNING)
.set(COLUMN_NAME_STATUS, QueueBuildStatusEnum.FINISH);
update(wrapper);
}
}
根据方案二修改后
能正常获取事件。
@Getter
public class QueueBuildCompletedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {
private T data;
public QueueBuildCompletedEvent(T data) {
super(data);
this.data = data;
}
@Override
public ResolvableType getResolvableType() {
return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource()));
}
}
@Async
@EventListener
@Override
public void onQueueBuildCompletedEvent(QueueBuildCompletedEvent<String> event) {
log.error("我接收到事件了:{}", event);
String buildUuid = event.getData();
if (!StringUtils.isEmpty(buildUuid)) {
UpdateWrapper<QueueBuildDO> wrapper = new UpdateWrapper<QueueBuildDO>()
.eq(COLUMN_NAME_BUILD_UUID, buildUuid)
.eq(COLUMN_NAME_STATUS, QueueBuildStatusEnum.RUNNING)
.set(COLUMN_NAME_STATUS, QueueBuildStatusEnum.FINISH);
update(wrapper);
}
}
原理
待续吧,暂时么得空了