这是第二次尝试,通过修改的演示代码,希望能更好地说明这个问题。代码已经被剥离,除去了所有的元素,除了那些演示正在遇到的问题的元素。
添加注意:一些额外的测试做了,结果张贴作为一个答案(副扩展这篇文章)。这可能是“预期的行为”,但我仍在努力理解“为什么”。
代码“起作用”,因为它返回预期的信息(字符串或字符串列表)。但是,当使用WebClient访问返回流量的RESTendpoint(localhost:8080/test/democlient)时,会对关联的处理程序(DemoMainHandler.getAll())进行两次调用。我不知道在DemoMainHandler.getAll()上的第二个调用是在哪里进行的,但我担心如果在生产环境中发生这种情况,可能会出现性能问题。
在所提供的代码中,所有内容都在单个Spring Webflux应用程序下运行,因此DemoClient代码没有单独的进程。
但是,访问localhost:8080/test/democlient上的RESTendpoint会产生一些相关的结果。通过Flux返回给Postman的字符串值看起来还可以,但是
我不理解的是,为什么DemoclientHandler.getAll()会被第二次调用,如控制台的第二个system.out.println()输出所示。它似乎与使用通量作为返回类型有关?
控制台输出
2019-10-07 08:16:18.953 INFO 9384 --- [ main] c.example.testdupe.TestDupeApplication : Starting TestDupeApplication on M7730-LFR with PID 9384 (D:\sandbox\TestDupe\build\classes\java\main started by LesR in D:\sandbox\TestDupe)
2019-10-07 08:16:18.953 INFO 9384 --- [ main] c.example.testdupe.TestDupeApplication : No active profile set, falling back to default profiles: default
2019-10-07 08:16:20.062 INFO 9384 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port(s): 8080
2019-10-07 08:16:20.062 INFO 9384 --- [ main] c.example.testdupe.TestDupeApplication : Started TestDupeApplication in 1.324 seconds (JVM running for 1.871)
***** Invoke localhost:8080/test/DemoClient/{id}
DemoClientHandler.getById( ServerRequest )
DemoClient.getById( 2 )
DemoMainHandler.getById( ServerRequest )
***** Invoke localhost:8080/test/DemoClient
DemoClientHandler.getAll( ServerRequest )
DemoClientHandler.getAll() >> BEFORE invoking demoClient.getAll()
DemoClient.getAll()
DemoClient.getAll() >> RETURN fluxString
DemoClientHandler.getAll() >> AFTER invoking demoClient.getAll()
DemoMainHandler.getAll( ServerRequest )
DemoMainHandler.getAll( ServerRequest )
示例代码
@SpringBootApplication
public class TestDupeApplication {
public static void main(String[] args) {
SpringApplication.run(TestDupeApplication.class, args);
}
}
@Configuration
public class DemoClientRouter {
@Bean
public RouterFunction<ServerResponse> clientRoutes(DemoClientHandler requestHandler) {
return nest(path("/test"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/DemoClient"), requestHandler::getAll)
.andRoute(Requesthtml" target="_blank">Predicates.GET("/DemoClient/{id}"), requestHandler::getById)));
}
}
@Component
public class DemoClientHandler {
@Autowired
DemoClient demoClient;
public Mono<ServerResponse> getAll(ServerRequest request) {
System.out.println("DemoClientHandler.getAll( ServerRequest )");
System.out.println("DemoClientHandler.getAll() >> BEFORE invoking demoClient.getAll()");
Flux<String> fluxString = demoClient.getAll();
System.out.println("DemoClientHandler.getAll() >> AFTER invoking demoClient.getAll()");
return fluxString.hasElements().flatMap(hasElement -> {
return hasElement ? ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(fluxString, String.class)
: ServerResponse.noContent().build();
});
}
public Mono<ServerResponse> getById(ServerRequest request) {
System.out.println("DemoClientHandler.getById( ServerRequest )");
Mono<String> monoString;
return demoClient.getById( 2 ).flatMap(stringVal -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(stringVal), String.class))
.switchIfEmpty(ServerResponse.notFound().build());
}
}
@Component
public class DemoClient {
private final WebClient client;
public DemoClient() {
client = WebClient.create();
}
public Flux<String> getAll() {
System.out.println("DemoClient.getAll()");
Flux<String> fluxString;
fluxString = client.get().uri("http://localhost:8080/test/DemoMain")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMapMany(response -> response.bodyToFlux(String.class));
// fluxString = client.get().uri("http://localhost:8080/test/DemoMain")
// .accept(MediaType.APPLICATION_JSON)
// .retrieve()
// .bodyToFlux(String.class);
System.out.println("DemoClient.getAll() >> RETURN fluxString");
return fluxString;
}
public Mono<String> getById(int id) {
System.out.printf("DemoClient.getById( %d )%n", id);
return client.get().uri("http://localhost:8080/test/DemoMain/" + id)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMap(response -> response.bodyToMono(String.class));
}
}
@Configuration
public class DemoMainRouter {
@Bean
public RouterFunction<ServerResponse> demoPOJORoute(DemoMainHandler requestHandler) {
return nest(path("/test"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.GET("/DemoMain"), requestHandler::getAll)
.andRoute(RequestPredicates.GET("/DemoMain/{id}"), requestHandler::getById)));
}
}
@Component
public class DemoMainHandler {
public Mono<ServerResponse> getAll(ServerRequest request) {
System.out.println("DemoMainHandler.getAll( ServerRequest )");
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Flux.just("Call", "Me", "Once"), String.class);
}
public Mono<ServerResponse> getById(ServerRequest request) {
System.out.println("DemoMainHandler.getById( ServerRequest )");
return ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(Mono.just("Only One"), String.class);
}
}
添加此代码是为了支持后续讨论...
@Component
public class DemoClient {
private final WebClient client;
public DemoClient() {
client = WebClient.create();
}
public Flux<String> getAll() {
Flux<String> fluxString;
Mono<ClientResponse> monoCR = client.get().uri("http://localhost:8080/test/DemoMain")
.accept(MediaType.APPLICATION_JSON)
.exchange();
fluxString = monoCR.flatMapMany(clientResponse -> clientResponse.bodyToFlux(String.class));
// fluxString.subscribe();
// return fluxString;
return Flux.just("Foo", "Bar");
}
后续讨论。不是一个真正的答案,但感觉它的方向是正确的。
修改了democlient.gatall()来“解链”通量/流上的操作,希望获得一些洞察力。以下是我做的/发现的:
当我注释掉fluxString.subscribe()'并返回fluxString时;语句,则DemoMainHandler.getAll()没有输出。我想这“并不奇怪”,因为生成的Flux上没有订阅任何东西,所以没有调用DemoMainHandler.getAll(),因为不需要Flux。
当我取消对fluxString.subscribe()的注释时;但保留返回FluxString;注释后,我看到了DemoMainHandler.getAll()的一个println()输出。再一次,我认为这是“不是一个意外”,因为通量现在是订阅的,即使没有做任何结果。因此,DemoMainHandler.getAll()被调用并输出其println()内容。
最后,我注释掉了fluxString.subscribe();并返回flux.just(“foo”,“bar”);语句,以及未注释的*return fluxString;“。这会从DemoMainHandler.getAll()中产生我一直询问的两个println()输出。
基于订阅返回的Flux的结果,我假设DemoMainHandler.getAll()输出的第一个println()是代表Postman(即“最终消费者”)隐式订阅的结果。但是,这仍然给我留下了一个问题:“为什么DemoMainHandler.getAll()的第二个println()输出?”Reactor真的在订阅时调用DemoMainHandler.getAll()一次,在处理实际内容时再调用一次吗?还是?
代码“起作用”,因为它返回预期的信息(DemoPOJO对象列表)。但是,如下所示的控制台输出所示,正在对localhost上的REST服务进行两次调用:8080/v2/demopojo。我有一种感觉,第二次调用是对反应编程缺乏了解的结果,但我不知道第二次调用是在这个REST API上进行的,我想消除它,因为当部署“实际的东西”时,冗余很可能是一个性能问题。 在提供的代码中,在localhost:8
问题内容: 我有这样的代码: 每次尝试访问它时,总会出现恐慌。 像这个: 我以为我可以访问从我设置为全局变量。当我将数据库初始化移动到错误不会出现。 我的代码中哪些部分是错误的? 另外,我是Golang的新手。如果您对如何组织我的代码有任何建议,请告诉我。谢谢.. :) 问题答案: 您的函数中的db变量正在遮盖全局变量。执行此操作时: 它将其分配给新的局部变量db。这是因为它不是来自同一块。根据标
我想在JavaFX中制作一个程序,其中包含一个按钮,单击该按钮时,将创建一个圆并将其添加到形状的ArrayList中。以下是我的代码: 我的问题是-如何从内部句柄方法访问“circle1”?在JavaScript中,我们使用e.currentTarget。 我无法声明“Circle1”最终版本,因为我需要在之后更改它。
我试图通过在Spring Boot中配置的REST APIendpoint从AWS Secrets Manager获取凭据。如果我在endpoint的URL中键入参数,我就会得到所需的对象。具有endpoint的站点也通过AWS托管。 当我尝试从Angular development server访问endpoint时,我总是得到401个未经授权的权限。我使用Angular的代理来访问跨域endp
我试图从Java连接到MySQL,但我得到以下错误。 谢谢你的帮助,我对此很陌生。我肯定密码和用户名是正确的,所以我不确定从这里去哪里。下面是我连接数据库的代码:
注意:下面是对类似帖子/问题的编辑/修订,试图更好地识别我的问题/问题,并提供更好的代码示例来演示我的问题。 添加注意:代码示例已修改为包括工作代码。 我在同一个spring reactive应用程序中的两台路由器中有两个endpoint。第一个(/v2/demopojo)似乎可以正常工作。第二个(/v2/democlient/demopojo),使用WebClient委托给/v2/demopoj