Вызов метода Spring-контроллера без выхода в интернет - PullRequest
0 голосов
/ 04 марта 2019

tldr: Есть ли способ сделать внутренний запрос (используя путь метода) без выхода в Интернет?

-

Зачем мне нужноЭто?У меня есть проект, который получает много событий.Решение о том, кто будет обрабатывать каждое событие, принимается контроллером.Итак, у меня есть что-то похожее на это:

@RestController
@RequestMapping("/events")
public class EventHandlerAPI {

    @Autowired 
    private EventAHandler eventAhandler;
    @Autowired 
    private EventBHandler eventBhandler;

    @PostMapping("/a")
    public void handleEventA(@RequestBody EventA event) {
       eventAhandler.handle(id, event);
    }

    @PostMapping("/b")
    public void handleEventB(@RequestBody EventB event) {
       eventBhandler.handle(id, event);
    }

}

Мы недавно добавили поддержку для получения событий через службу очереди.Он отправляет нам полезную нагрузку и класс события.Наше решение состоит в том, чтобы оба интерфейса работали (отдых и очередь).Решение, позволяющее избежать дублирования кода, состояло в том, чтобы Контроллер выбирал, какой обработчик позаботится о событии.Код в настоящее время похож на этот:

@Configuration
public class EventHandlerQueueConsumer {

    @Autowired 
    private EventHandlerAPI eventHandlerAPI;

    private Map<Class, EventHandler> eventHandlers;

    @PostConstruct 
    public void init() { 
        /* start listen queue */ 
        declareEventHandlers();
    }

    private void declareEventHandlers() {
        eventHandlers = new HashMap<>();
        eventHandlers.put(EventAHandler.class, (EventHandler<EventAHandler>) eventHandlerAPI::handleEventA);
        eventHandlers.put(EventBHandler.class, (EventHandler<EventBHandler>) eventHandlerAPI::handleEventB);
    }

   private void onEventReceived(AbstractEvent event) {
       EventHandler eventHandler = eventHandlers.get(event.getClass());
       eventHandler.handle(event);
   }

    private interface EventHandler<T extends AbstractEvent> {
        void handle(T event);
    }

}

Этот код работает, но он не позволяет контролеру выбирать, кто будет обрабатывать событие (наше намерение).Решение на самом деле принимается картой.

Я хотел бы вызвать метод контроллера через сопоставление его запросов, не выходя в Интернет.Примерно так:

@Configuration
public class EventHandlerQueueConsumer {

    // MADE UP CLASS TO SHOW WHAT I WANT
    @Autowired
    private ControllerInkover controllerInvoker;

    @PostConstruct 
    public void init() { /* start listen queue */ }

   private void onEventReceived(AbstractEvent event) {
       controllerInvoker.post(event.getPath(), new Object[] { event });
   }

}

Этот способ намного чище и позволяет всем решениям принимать контроллер.

Я много исследовал и не нашел способа реализовать это.Отладка пружины, я нашел, как он направляет запрос после DispatcherServlet, но все внутренние пружины используют HttpServletRequest и HttpServletResponse: (

Есть ли способ сделать внутренний запрос (с использованием методапуть) не выходя в интернет?

1 Ответ

0 голосов
/ 05 марта 2019

Это классы одного и того же приложения.

Тогда это должно быть достаточно просто.

1) Вы можете вызвать свой собственный API на http(s)://localhost:{port}/api/{path}, используя RestTemplateслужебный класс.Это предпочтительный способ, так как вы будете следовать стандартному шаблону MVC.Что-то вроде:

restTemplate.exchange(uri, HttpMethod.POST, httpEntity, ResponseClass.class);

2) Если вы вообще не хотите вызывать сетевое соединение, то вы можете либо использовать внутреннее Spring, чтобы найти карту отображения / метода, либо использовать некоторое отражение для построения пользовательской карты на основезапуск контроллера.Затем вы можете передать свое событие / объект методу с карты так, как показано в вашем классе макета.Что-то вроде:

@RequestMapping("foo")
 public void fooMethod() {
    System.out.println("mapping = " + getMapping("fooMethod")); // you can get all methods/mapping in @PostContruct initialization phase
 }

 private String getMapping(String methodName) {
    Method methods[] = this.getClass().getMethods();
    for (int i = 0; i < methods.length; i++) {
        if (methods[i].getName() == methodName) {
            String mapping[] = methods[i].getAnnotation(RequestMapping.class).value();
            if (mapping.length > 0) {
                return mapping[mapping.length - 1];
            }
        }
    }
    return null;
}
...