Весна Избегайте круговой зависимости - PullRequest
0 голосов
/ 05 июля 2019

Работая над созданием небольшой библиотеки Bus / Mediator, я столкнулся с проблемой, пытаясь заставить ее работать с Spring.Посредник принимает команды и события и направляет их в соответствующий CommandHandler или EventHandler.Моя проблема возникает, когда мне нужно ввести Mediator в класс Handler.Я получаю циклическую ссылку, потому что моему контроллеру нужно ввести Mediator, Mediator нужен Handler, а Handler нужен медиатор.Идея того, как это должно работать, заключается в том, что команды приходят в систему и отправляются классу обработчика.Затем, если что-то случится, класс обработчика отправит событие, чтобы любой заинтересованный слушатель мог быть уведомлен и принять меры.По сути это очень простой и легкий CQRS + Event Souring.

Я регистрирую компоненты с помощью посредника, получая все компоненты, реализующие интерфейсы обработчика, и затем проверяю их аргументы универсального типа.

  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;
  }
}

Даже если вместо этого я использую сеттер / инжекцию поля, я все равно получаю круговую ссылку.Я также пытался пометить бобы @Lazy, но это не имело значения.Сейчас я думаю, что мой единственный вариант - разделить CommandBus и EventBus на разные компоненты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...