春季5反应堆中控制器与路由器的区别

时间:2017-11-03 09:12:46

标签: spring reactive spring-webflux

现在有两种方法可以在Spring 5中公开http端点。

  1. 控制器:通过制作休息控​​制器。

    @RestController
    @RequestMapping("test")
    public class QuestionController {
    ...
    }
    
  2. 路由器:路由器。例如:

    RouterFunction<?> route = route(GET("/person/{id}"),
    request -> {
    Mono<Person> person = Mono.justOrEmpty(request.pathVariable("id"))
    .map(Integer::valueOf)
    .then(repository::getPerson);
    return Response.ok().body(fromPublisher(person, Person.class));
    })
    
  3. 使用任何一种方法有任何性能差异吗?从头开始编写应用程序时,我应该使用哪一个。

2 个答案:

答案 0 :(得分:4)

虽然有些晚,但这可能对将来的读者有用。

通过切换到功能路由声明:

  1. 您将所有路由配置都保存在一个地方
  2. 在访问传入的请求参数,路径变量和请求的其他重要组成部分方面,您将获得与基于注释的常规方法几乎相同的灵活性
  3. 您可以避免运行整个Spring Framework基础结构,这可能会减少应用程序的启动时间

关于第3点,在某些情况下,Spring生态系统的整个功能(IoC,注释处理,自动配置)可能是冗余的,因此减少了应用程序的总体启动时间。

在微型微服务,Amazon Lambdas和类似云服务的时代,提供允许开发人员创建具有几乎相同框架功能的轻量级应用程序的功能非常重要。这就是Spring Framework团队决定将此功能集成到WebFlux模块中的原因。

新的功能性Web框架使您无需启动整个Spring基础结构即可构建Web应用程序。在这种情况下,main方法应类似于以下内容(注意,没有@SpringBootApplication注释)

class StandaloneApplication { 
    public static void main(String[] args) { 
        HttpHandler httpHandler = RouterFunctions.toHttpHandler(
           routes(new BCryptPasswordEncoder(18))
        ); 

        ReactorHttpHandlerAdapter reactorHttpHandler = new ReactorHttpHandlerAdapter(httpHandler); 

        HttpServer.create() 
            .port(8080) 
            .handle(reactorHttpHandler) 
            .bind() 
            .flatMap(DisposableChannel::onDispose) 
            .block(); 
    }

    static RouterFunction<ServerResponse> routes(PasswordEncoder passwordEncoder ) { 
        return
            route(
                POST("/check"), 
                request -> request 
                          .bodyToMono(PasswordDTO.class)
                          .map(p -> passwordEncoder 
                              .matches(p.getRaw(), p.getSecured())) 
                          .flatMap(isMatched -> isMatched 
                              ? ServerResponse 
                                  .ok() 
                                  .build() 
                              : ServerResponse 
                                  .status(HttpStatus.EXPECTATION_FAILED) 
                                  .build() 
                           ) 
                ); 
    }
}

答案 1 :(得分:0)

  • 编程范例:命令式与功能式

在使用@Controller@RestController批注的情况下,我们同意基于批注的模型,在该模型中,我们将批注(不仅是)用于映射,并因此产生了副作用(不是在功能界允许)以使我们的API能够正常工作。这样的副作用可能是@Valid注释,它为请求的主体提供了内置的bean验证,或者是@RequestMapping,它带有整个控制器的根路径。

另一方面,借助路由器功能,我们摆脱了在API实现方面包含任何副作用的注释,并将其直接委派给功能链:router -> handler。这两个非常适合构建基本的反应块:一个事件序列和两个主角,这些事件的发布者和订阅者。

  • MVC传统:Servlet堆栈与Netty堆栈

当我们谈论@Controller时,我会说我们通常会用同步Java世界来思考:ServletsServletContextServletContainerInitializer,{{1} }等。即使我们从控制器返回DispatcherServlet以使我们的应用程序具有响应性,我们仍然会按照Mono规范运行,该规范支持Servlet 3.0并在相同的servlet容器上运行,例如java.nio.*Jetty。随后,在这里,我们将使用相应的设计模式和方法来构建Web应用程序。

另一方面,

Tomcat受到了真正的反应式方法的启发,该方法源自异步Java世界-Netty及其RouterFunction

随后出现了一组新的类及其用于反应性环境的API:ServerRequestServerResponseWebFilter等。对于我来说,它们是由Spring团队根据前几年的设计而设计的,这些年来保持框架并了解新的Web系统要求。这些要求的名称为Reactive Manifesto

真实案例

最近,我的团队遇到了无法将SwaggerChannel Model端点集成的问题。它可以为RouterFucntion投票,但是Spring团队介绍了他们的解决方案-Spring REST Docs,可以很容易地将其连接到反应性WebTestClient。我在这里使用“已连接”一词,是因为它具有真正的反应性含义:与具有重载配置和副作用注释的Swagger相比,您可以轻松地在测试中构建API文档,而完全不动手。

最终位

由于不影响性能,因此可能会听到类似于“它完全基于个人偏好使用什么”的信息。我同意,个人的偏爱确实有两个选择:当您让自己在同一个领域呆了十年时,前进还是后退。我认为Spring团队为@Controlers提供了响应式支持,以使旧项目能够以某种方式与时间需求保持一致,并且至少有迁移的机会。 如果您要从头开始创建Web应用程序,请不要犹豫并使用引入的反应式堆栈。