diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java index 2e47022d3..6f49f044d 100644 --- a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/WorkflowEngineStarterAutoConfiguration.java @@ -24,6 +24,7 @@ import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerNotificationEventList import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerTaskEventListener; import cn.axzo.workflow.starter.mq.broadcast.consumer.InnerWorkflowListener; import cn.axzo.workflow.starter.mq.check.ImplementationChecker; +import cn.axzo.workflow.starter.mq.check.ImplementationReadyChecker; import cn.axzo.workflow.starter.mq.monitor.WorkflowEngineStarterDefaultMQMonitor; import cn.axzo.workflow.starter.mq.monitor.console.WorkflowEngineStarterMQMonitorController; import cn.axzo.workflow.starter.selector.MetaFeignClientEnableSelector; @@ -161,4 +162,9 @@ public class WorkflowEngineStarterAutoConfiguration { return new ImplementationChecker(); } + @Bean + public ImplementationReadyChecker implementationReadyChecker() { + return new ImplementationReadyChecker(); + } + } diff --git a/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/check/ImplementationReadyChecker.java b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/check/ImplementationReadyChecker.java new file mode 100644 index 000000000..6a5cf3361 --- /dev/null +++ b/workflow-engine-spring-boot-starter/src/main/java/cn/axzo/workflow/starter/mq/check/ImplementationReadyChecker.java @@ -0,0 +1,98 @@ +package cn.axzo.workflow.starter.mq.check; + +import cn.axzo.workflow.starter.handler.ProcessInstanceEventHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * Starter MQ 监听实现检查 + * + * @author wangli + * @since 2025-08-25 20:06 + */ +@Slf4j +public class ImplementationReadyChecker implements ApplicationListener { + + private static final Class TARGET_INTERFACE = ProcessInstanceEventHandler.class; + // 要检查的方法列表,顺序对应二进制位的位置(从左到右) + private static final List METHOD_NAMES = Arrays.asList( + "onCompleted", + "onCancelled", + "onRejected", + "onAborted" + ); + + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + ApplicationContext context = event.getApplicationContext(); + // 获取所有实现了目标接口的Bean + Map handlers = context.getBeansOfType(TARGET_INTERFACE); + if (handlers.isEmpty()) { + // 如果没有找到任何实现类,可以选择抛出异常或记录警告 + log.info("未找到实现 " + TARGET_INTERFACE.getName() + " 接口的Bean, 请确保至少有一个实现类被正确扫描和注册。"); +// throw new IllegalStateException("未找到实现 " + TARGET_INTERFACE.getName() + " 接口的Bean, 请确保至少有一个实现类被正确扫描和注册。"); + } + + // 记录每个方法是否被实现 + boolean[] methodImplemented = new boolean[4]; + Arrays.fill(methodImplemented, false); + + // 检查每个实现类 + for (ProcessInstanceEventHandler handler : handlers.values()) { + Class handlerClass = handler.getClass(); + + // 检查每个方法是否被当前实现类覆盖 + for (int i = 0; i < METHOD_NAMES.size(); i++) { + String methodName = METHOD_NAMES.get(i); + try { + Method method = handlerClass.getMethod(methodName); + // 检查方法是否来自接口本身(如果是默认方法)还是实现类 + if (method.getDeclaringClass() != ProcessInstanceEventHandler.class) { + methodImplemented[i] = true; + } + } catch (NoSuchMethodException e) { + // 方法未被实现,保持默认值false + } + } + } + + // 生成4位二进制数 + int binaryResult = 0; + for (int i = 0; i < methodImplemented.length; i++) { + if (methodImplemented[i]) { + // 计算当前位对应的权重(第一位是8,第二位是4,以此类推) + int weight = (int) Math.pow(2, 3 - i); + binaryResult += weight; + } + } + + // 收集未实现的方法 + List unimplementedMethods = new ArrayList<>(); + for (int i = 0; i < methodImplemented.length; i++) { + if (!methodImplemented[i]) { + unimplementedMethods.add(METHOD_NAMES.get(i)); + } + } + + log.info("实现 {} 接口的Bean数量: {}", TARGET_INTERFACE.getName(), handlers.size()); + log.info("方法实现情况:(二进制:{}),(十进制:{})", String.format("%4s", Integer.toBinaryString(binaryResult)).replace(' ', '0'), binaryResult); + if (!unimplementedMethods.isEmpty()) { + log.info("以下方法未被任何实现类覆盖: " + String.join(", ", unimplementedMethods) + + "。请确保至少有一个实现类覆盖这些方法以处理相应的事件。"); +// throw new IllegalStateException("以下方法未被任何实现类覆盖: " + String.join(", ", unimplementedMethods) + +// "。请确保至少有一个实现类覆盖这些方法以处理相应的事件。"); + } else { + log.info("Congratulations, passed the verification!"); + log.info("祝贺,已通过校验!"); + } + } +}