#java #spring #generics #dependency-injection
#java #весна #дженерики #внедрение зависимостей
Вопрос:
У меня есть интерфейс:
public interface CommandHandler<T extends Command> {
void handle(T command);
}
Существуют команды, которые реализуют интерфейс маркера команд
public class CreateCategoryCommand implements Command {
}
public class CreateCategoryCommand implements Command {
}
Для каждой команды у меня есть соответствующие реализации CommandHandler:
@Component
public class CreateProductCommandHandler implements CommandHandler<CreateProductCommand> {
@Override
public void handle(CreateProductCommand command) {
System.out.println("Command handled");
}
}
@Component
public class CreateCategoryCommandHandler implements CommandHandler<CreateCategoryCommand> {
@Override
public void handle(CreateCategoryCommand command) {
}
}
Вопрос:
У меня есть командная шина
@Component
public class SimpleCommandBus implements CommandBus {
@Autowired
private ApplicationContext context;
@Override
public void send(Command command) {
// OF COURSE, THIS NOT COMPILED, BUT I NEED SOMETHING LIKE THIS
CommandHandler commandHandler = context.getBean(CommandHandler<command.getClass()>)
}
}
Как получить компонент из контекста приложения, который реализует универсальный интерфейс с определенным типом?
Комментарии:
1. @Autowired private CommandHandler<CreateProductCommand> createProductCommandHandler; Не сработало для вас? или автоматически подключенный закрытый список <CommandHandler<?>> CommandHandlers; чтобы получить их все?
2. Мне нужно динамически получать класс CreateProductCommand. Я не хочу ставить @Autowired private CommandHandler<COMMAND_TYPE> для каждого типа команды в классе SimpleCommandBus.
3. Вы заметили мой обновленный комментарий о том, как вы можете автоматически подключать их все в виде списка @Autowired List<CommandHandler<?>> CommandHandlers; Вы также можете выполнить ApplicationContext.getBeansOfType(CommandHandler.class >
4. Да, спасибо. Хорошо, у меня есть все обработчики команд. Как я могу получить конкретный обработчик команд для данной команды (например, дочерняя команда) из этого списка? Например, как я могу получить CommandHandler для CreateProductCommand?
5. для конкретной реализации ApplicationContext.getBean(«createProductCommandHandler «);
Ответ №1:
Как я это решил:
@Component
public class SimpleCommandBus {
private final Logger logger;
private final Set<CommandHandler<?>> handlers;
private final Map<Class<?>, CommandHandler<?>> commandHandlersCache = new WeakHashMap<>();
public SimpleCommandBus(Logger logger, Set<CommandHandler<?>> handlers) {
this.logger = logger;
this.handlers = handlers;
}
public void send(Command command) {
CommandHandler<Command> commandHandler = getCommandHandler(command);
if (commandHandler != null)
commandHandler.handle(command);
else
logger.error("Can't handle command " command);
}
@SuppressWarnings("unchecked")
private <C extends Command> CommandHandler<C> getCommandHandler(C command) {
Class<?> commandType = command.getClass();
if (commandHandlersCache.containsKey(commandType))
return (CommandHandler<C>) commandHandlersCache.get(commandType);
for (CommandHandler<?> haandler : handlers) {
Class<?> supportedCommandType = resolveTypeArgument(haandler.getClass(), CommandHandler.class);
if (commandType.isAssignableFrom(supportedCommandType)) {
commandHandlersCache.put(commandType, haandler);
return (CommandHandler<C>) haandler;
}
}
commandHandlersCache.put(commandType, null);
return null;
}
}