代码“有效”,因为它返回了预期的信息(DemoPOJO对象的列表)。但是,如下面的控制台输出所示,在localhost:8080 / v2 / DemoPOJO处对REST服务进行了两次调用。我感觉第二个调用是由于缺乏对反应式编程的了解,但是我看不到在此REST API上进行第二个调用的位置,并希望消除它,因为可能会产生冗余部署“真实事物”时出现性能问题。
在提供的代码中,对localhost:8080 / v3 / DemoClient(在DemoClientHandler]中实现)进行了调用,然后使用WebClient对象访问位于localhost:8080 / v2 / DemoPOJO的相应REST服务(在DemoPOJOHandler中实现。
((我已将代码剥离为仅与REST端点/ v3 / DemoClient相关的那些语句)
)访问“第一级” REST API2019-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
“第二级”处理程序,通过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
)REST API的路由器...
@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(); } }
代码“有效”,因为它返回了预期的信息(DemoPOJO对象的列表)。但是,如下面所示的控制台输出所示,正在...
可能违反了某些规则,但是我尝试改写问题并在Why is the handler for a REST endpoint being accessed twice, when accessed from a WebClient?处收紧代码示例。
对于mod,我正在尝试避免对原始问题进行过多的编辑,因为这会使注释显得非主题。