在创建小型Bus / Mediator库时,在尝试使其与Spring一起使用时遇到了一个问题。介体接收命令和事件,并将它们路由到适当的CommandHandler或EventHandler。当我需要将调解器注入Handler类时,会发生我的问题。我得到一个循环引用,因为我的控制器需要注入Mediator,Mediator需要Handler,而Handler需要Mediator。应该如何工作的想法是命令进入系统并分派给处理程序类。然后,如果发生某种情况,处理程序类将调度一个事件,以便可以通知任何感兴趣的侦听器并采取措施。本质上,这是一个非常简单轻巧的CQRS +事件跟踪。
我正在通过获取实现了处理程序接口的所有bean,然后查看其通用类型参数来向中介程序注册组件。
public static Mediator createMediator(ApplicationContext applicationContext) {
if (applicationContext == null) {
throw new IllegalArgumentException("applicationContext cannot be null");
}
DefaultMediator mediator = new DefaultMediator();
registerCommandHandlers(mediator, applicationContext);
registerEventHandlers(mediator, applicationContext);
registerRequestHandlers(mediator, applicationContext);
return mediator;
}
@SuppressWarnings("unchecked")
private static void registerRequestHandlers(DefaultMediator mediator, ApplicationContext applicationContext) {
String[] beanNames = applicationContext.getBeanNamesForType(RequestHandler.class);
for (String name: beanNames) {
RequestHandler<?, ?> handler = (RequestHandler<?, ?>) applicationContext.getBean(name);
Class<?>[] generics = GenericTypeResolver.resolveTypeArguments(handler.getClass(), RequestHandler.class);
if (generics != null && generics.length > 0) {
Class<Request> type = (Class<Request>) generics[0];
mediator.registerRequestHandler(type, handler);
}
}
}
@SuppressWarnings("unchecked")
private static void registerCommandHandlers(DefaultMediator mediator, ApplicationContext applicationContext) {
String[] beanNames = applicationContext.getBeanNamesForType(CommandHandler.class);
for (String name : beanNames) {
CommandHandler<?> handler = (CommandHandler<?>) applicationContext.getBean(name);
Class<?>[] generics = GenericTypeResolver.resolveTypeArguments(handler.getClass(), CommandHandler.class);
if (generics != null && generics.length > 0) {
Class<Command> type = (Class<Command>) generics[0];
mediator.registerCommandHandler(type, handler);
}
}
}
@SuppressWarnings("unchecked")
private static void registerEventHandlers(DefaultMediator mediator, ApplicationContext applicationContext) {
String[] beanNames = applicationContext.getBeanNamesForType(EventHandler.class);
for (String name: beanNames) {
EventHandler<?> handler = (EventHandler<?>) applicationContext.getBean(name);
Class<?>[] generics = GenericTypeResolver.resolveTypeArguments(handler.getClass(), EventHandler.class);
if (generics != null && generics.length > 0) {
Class<Event> type = (Class<Event>) generics[0];
mediator.registerEventHandler(type, handler);
}
}
}
}
这是处理程序实现的样子。
@Component
public class CreateUserRequestHandler extends RequestHandler<CreateUserRequest, Boolean> {
private final Mediator mediator;
public CreateUserRequestHandler(Mediator mediator) {
this.mediator = mediator;
}
@Override
public Boolean handle(CreateUserRequest createUserRequest) {
System.out.println("Creating user with userName " + createUserRequest.getUserName());
return true;
}
}
即使我使用setter / field注入,我仍然可以获得循环引用。我也尝试过在@Lazy标记豆,这没有什么不同。现在,我认为我唯一的选择是将CommandBus和EventBus分成不同的组件。