Код «работает» в том смысле, что он возвращает ожидаемую информацию (список 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();
}
}