Spring避免循环依赖

时间:2019-07-05 17:02:01

标签: java spring dependency-injection

在创建小型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分成不同的组件。

0 个答案:

没有答案