Почему к конечной точке REST обращаются дважды, и можно ли исключить второй доступ? - PullRequest
0 голосов
/ 27 сентября 2019

Код «работает» в том смысле, что он возвращает ожидаемую информацию (список DemoPOJO объектов).Однако, как показано в выводе консоли, показанном ниже, в службу REST делается два вызова по адресу localhost: 8080 / v2 / DemoPOJO .У меня есть ощущение, что второй вызов является результатом недостаточного понимания реактивного программирования, но я не вижу, где выполняется второй вызов для этого REST API, и хотел бы устранить его, так как избыточность, вероятно, будетпроблема производительности при развертывании «чего-то реального».

В предоставленном коде выполняется вызов на localhost: 8080 / v3 / DemoClient (реализован в DemoClientHandler ), который затем используетОбъект WebClient для доступа к соответствующей службе REST на локальном хосте: 8080 / v2 / DemoPOJO (реализовано в DemoPOJOHandler ).

(Я сократил код до тех операторов, которые связаны с конечной точкой REST/ v3 / DemoClient)

2019-09-26 12:30:23.389  INFO 4260 --- [           main] com.test.demo.DemoApplication            : Starting DemoApplication on M7730-LFR with PID 4260 (D:\sandbox\DemoReactive\build\classes\java\main started by LesR in D:\sandbox\DemoReactive)
2019-09-26 12:30:23.391  INFO 4260 --- [           main] com.test.demo.DemoApplication            : No active profile set, falling back to default profiles: default
2019-09-26 12:30:24.570  INFO 4260 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2019-09-26 12:30:24.573  INFO 4260 --- [           main] com.test.demo.DemoApplication            : Started DemoApplication in 1.41 seconds (JVM running for 1.975)
2019-09-26 12:30:28.796  INFO 4260 --- [ctor-http-nio-3] m.n.d.accesslogger.ServiceRequestLogger  : 
    *****  Begin, Access Request Log
    Service request    -> GET @ http://localhost:8080/v3/DemoClient
    Service handled by -> com.test.demo.democlient.DemoClientHandler.getAll()
    *****  End, Access Request Log
2019-09-26 12:30:28.823  INFO 4260 --- [ctor-http-nio-8] m.n.d.accesslogger.ServiceRequestLogger  : 
    *****  Begin, Access Request Log
    Service request    -> GET @ http://localhost:8080/v2/DemoPOJO
    Service handled by -> com.test.demo.demopojo.DemoPOJOHandler.getAll()
    *****  End, Access Request Log
2019-09-26 12:30:28.911  INFO 4260 --- [ctor-http-nio-9] m.n.d.accesslogger.ServiceRequestLogger  : 
    *****  Begin, Access Request Log
    Service request    -> GET @ http://localhost:8080/v2/DemoPOJO
    Service handled by -> com.test.demo.demopojo.DemoPOJOHandler.getAll()
    *****  End, Access Request Log

Обработчик «второго уровня», доступ к REST API «первого уровня» через WebClient ( DemoClient )

@Component
public class DemoClientHandler {

    public static final String PATH_VAR_ID = "id";

    @Autowired
    ServiceRequestLogger svcRequestLogger;

    @Autowired
    DemoClient demoClient;

    public Mono<ServerResponse> getAll(ServerRequest request) {
        Flux<DemoPOJO> fluxDemoPOJO = demoClient.getAll();

        svcRequestLogger.logServiceRequest(this.getClass(), "getAll()", request);

        return fluxDemoPOJO.hasElements().flatMap(hasElement -> {
            return hasElement ? ServerResponse.ok()
                                              .contentType(MediaType.APPLICATION_JSON)
                                              .body(fluxDemoPOJO, DemoPOJO.class)
                              : ServerResponse.noContent().build();
        });
    }
}

Использование WebClient для доступа к REST API "первого уровня" ...

@Component
public class DemoClient {

    private final WebClient client;

    public DemoClient() {
        client = WebClient.create();
    }

    public Flux<DemoPOJO> getAll() {
        return client.get().uri("http://localhost:8080/v2/DemoPOJO")
                           .accept(MediaType.APPLICATION_JSON)
                           .exchange()
                           .flatMapMany(response -> response.bodyToFlux(DemoPOJO.class));
    }
)

Обработчик "первого уровня" ...

@Component
public class DemoPOJOHandler {

    @Autowired
    private ServiceRequestLogger svcRequestLogger;

    @Autowired
    private DemoPOJOService service;

    public Mono<ServerResponse> getAll(ServerRequest request) {
        Flux<DemoPOJO> fluxDemoPOJO = service.getAll();

        svcRequestLogger.logServiceRequest(this.getClass(), "getAll()", request);

        return fluxDemoPOJO.hasElements().flatMap(hasElement -> {
            return hasElement ? ServerResponse.ok()
                                              .contentType(MediaType.APPLICATION_JSON)
                                              .body(fluxDemoPOJO, DemoPOJO.class)
                              : ServerResponse.noContent().build();
        });
    }
}

Маршрутизатор для второго-уровень ( WebClient ) RESTAPI ...

@Configuration
public class DemoClientRouter {

    @Bean
    public RouterFunction<ServerResponse> clientRoutes(DemoClientHandler requestHandler) {
        return nest(path("/v3"),
                nest(accept(APPLICATION_JSON),
                        RouterFunctions.route(RequestPredicates.GET("/DemoClient"), requestHandler::getAll)));
    }
}

Маршрутизатор для REST API первого уровня ...

@Configuration
public class DemoPOJORouter {

    @Bean
    public RouterFunction<ServerResponse> demoPOJORoute(DemoPOJOHandler requestHandler) {
        return nest(path("/v2"),
                nest(accept(APPLICATION_JSON),
                        RouterFunctions.route(RequestPredicates.GET("/DemoPOJO"), requestHandler::getAll)));
    }
}

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

Сервисный уровень, поддерживает операции DemoPOJO ...

@Component
public class DemoPOJOService {

    @Autowired
    private DemoPOJORepo demoPOJORepo;

    public Flux<DemoPOJO> getAll() {
        return Flux.fromArray(demoPOJORepo.getAll());
    }
}

Простой макет POJO / данных для поддержки исследования ...

@Component
public class DemoPOJORepo {

    private static final int NUM_OBJS = 5;

    private static DemoPOJORepo demoRepo = null;

    private Map<Integer, DemoPOJO> demoPOJOMap;

    private DemoPOJORepo() {
        initMap();
    }

    public static DemoPOJORepo getInstance() {
        if (demoRepo == null) {
            demoRepo = new DemoPOJORepo();
        }
        return demoRepo;
    }

    public DemoPOJO[] getAll() {
        return demoPOJOMap.values().toArray(new DemoPOJO[demoPOJOMap.size()]);
    }

    private void initMap() {
        demoPOJOMap = new TreeMap<Integer, DemoPOJO>();

        for (int ndx = 1; ndx < (NUM_OBJS + 1); ndx++) {
            demoPOJOMap.put(ndx, new DemoPOJO(ndx, "foo_" + ndx, ndx + 100));
        }
    }
}

Журналы ( SLF4J / (Logback *) клиентский доступ служб REST к журналу приложения ...

@Component
public class ServiceRequestLogger {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    public void logServiceRequest(Class serviceHandler, String serviceMethod, ServerRequest request) {
        logger.info(buildLogMessage(serviceHandler, serviceMethod, request));
    }

    private String buildLogMessage(Class serviceHandler, String serviceMethod, ServerRequest request) {
        StringBuilder logMessage = new StringBuilder();

        /* <housekeeping code to build message to log */
        return logMessage.toString();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...