资讯专栏INFORMATION COLUMN

springboot(六)——springboot与webflux结合初探

hersion / 3577人阅读

摘要:的这几天看了看的请求处理流程,因为之前一直用的和,一开始对的处理流程有点懵逼,找不到入口,后来跟了代码,在网上找了点资料,发现的入口在的方法该方法的作用就是把接收到的或者最终需要返回的,包装转换为和。

spring-cloud-gateway 的ReactorHttpHandlerAdapter

这几天看了看spring-cloud-gateway的请求处理流程,因为之前一直用的springboot1.x和spring4,一开始对spring-cloud-gateway的处理流程有点懵逼,找不到入口,后来跟了代码,在网上找了点资料,发现spring-cloud-gateway的入口在ReactorHttpHandlerAdapter的apply方法

</>复制代码

  1. public class ReactorHttpHandlerAdapter implements BiFunction> {
  2. private static final Log logger = HttpLogging.forLogName(ReactorHttpHandlerAdapter.class);
  3. private final HttpHandler httpHandler;
  4. public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
  5. Assert.notNull(httpHandler, "HttpHandler must not be null");
  6. this.httpHandler = httpHandler;
  7. }
  8. @Override
  9. public Mono apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
  10. NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
  11. try {
  12. ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
  13. ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
  14. if (request.getMethod() == HttpMethod.HEAD) {
  15. response = new HttpHeadResponseDecorator(response);
  16. }
  17. return this.httpHandler.handle(request, response)
  18. .doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
  19. .doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
  20. }
  21. catch (URISyntaxException ex) {
  22. if (logger.isDebugEnabled()) {
  23. logger.debug("Failed to get request URI: " + ex.getMessage());
  24. }
  25. reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
  26. return Mono.empty();
  27. }
  28. }
  29. }

该方法的作用就是把接收到的HttpServerRequest或者最终需要返回的HttpServerResponse,包装转换为ReactorServerHttpRequest和ReactorServerHttpResponse。

spring-webflux

当然,这篇文章的主要内容不是谈论spring-cloud-gateway了,因为之前一直用的spring4,所以对spring5当中的反应式编程范式和webflux不太了解,所以先写个demo了解一下
第一步:引入相关pom,测试的相关pom根据自己的需要引入

</>复制代码

  1. org.springframework.boot
  2. spring-boot-starter-parent
  3. 2.1.4.RELEASE
  4. org.springframework.boot
  5. spring-boot-starter-webflux
  6. org.springframework.boot
  7. spring-boot-starter-test
  8. test
  9. io.projectreactor
  10. reactor-test
  11. test

第二步:创建一个HandlerFunction

</>复制代码

  1. public class TestFunction implements HandlerFunction {
  2. @Override
  3. public Mono handle(ServerRequest serverRequest) {
  4. return ServerResponse.ok().body(
  5. Mono.just(parse(serverRequest, "args1") + parse(serverRequest, "args2"))
  6. , Integer.class);
  7. }
  8. private int parse(final ServerRequest request, final String param) {
  9. return Integer.parseInt(request.queryParam(param).orElse("0"));
  10. }
  11. }

第三步:注入一个RouterFunction

</>复制代码

  1. @Configuration
  2. public class TestRouteFunction {
  3. @Bean
  4. public RouterFunction routerFunction() {
  5. return RouterFunctions.route(RequestPredicates.GET("/add"), new TestFunction());
  6. }
  7. }

第四步:在webflux中,也可以使用之前的java注解的编程方式,我们也创建一个controller

</>复制代码

  1. @RestController
  2. @RequestMapping("/api/test")
  3. public class HelloController {
  4. @RequestMapping("/hello")
  5. public Mono hello() {
  6. return Mono.just("hello world");
  7. }
  8. }

第五步:创建启动类

</>复制代码

  1. @SpringBootApplication
  2. public class Spring5DemoApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(Spring5DemoApplication.class, args);
  5. }
  6. }

第六步:启动项目,访问如下两个接口都可以

</>复制代码

  1. http://localhost:8080/api/test/hello
  2. http://localhost:8080/add?args1=2&args2=3
和spring-boot结合

通过上面的例子,我们看到基本的两个类:HandlerFunction和RouterFunction,同时webflux有如下特性:

异步非阻塞

响应式(reactive)函数编程,纯lambda表达式

不仅仅是在Servlet容器中tomcat/jetty中运行,同时支持NIO的Netty和Undertow中,实际项目中,我们往往与spring-boot项目结合,我们跟进代码可以看看spring-boot是在什么时候创建的server

一、SpringApplication

</>复制代码

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch();
  3. stopWatch.start();
  4. ConfigurableApplicationContext context = null;
  5. Collection exceptionReporters = new ArrayList<>();
  6. configureHeadlessProperty();
  7. SpringApplicationRunListeners listeners = getRunListeners(args);
  8. listeners.starting();
  9. try {
  10. ApplicationArguments applicationArguments = new DefaultApplicationArguments(
  11. args);
  12. ConfigurableEnvironment environment = prepareEnvironment(listeners,
  13. applicationArguments);
  14. configureIgnoreBeanInfo(environment);
  15. Banner printedBanner = printBanner(environment);
  16. context = createApplicationContext();
  17. exceptionReporters = getSpringFactoriesInstances(
  18. SpringBootExceptionReporter.class,
  19. new Class[] { ConfigurableApplicationContext.class }, context);
  20. prepareContext(context, environment, listeners, applicationArguments,
  21. printedBanner);
  22. refreshContext(context);
  23. afterRefresh(context, applicationArguments);
  24. stopWatch.stop();
  25. if (this.logStartupInfo) {
  26. new StartupInfoLogger(this.mainApplicationClass)
  27. .logStarted(getApplicationLog(), stopWatch);
  28. }
  29. listeners.started(context);
  30. callRunners(context, applicationArguments);
  31. }
  32. catch (Throwable ex) {
  33. handleRunFailure(context, ex, exceptionReporters, listeners);
  34. throw new IllegalStateException(ex);
  35. }
  36. try {
  37. listeners.running(context);
  38. }
  39. catch (Throwable ex) {
  40. handleRunFailure(context, ex, exceptionReporters, null);
  41. throw new IllegalStateException(ex);
  42. }
  43. return context;
  44. }

我们只分析入口,其它代码暂时不管,找到refreshContext(context);这一行进去

二、ReactiveWebServerApplicationContext的refresh()

</>复制代码

  1. @Override
  2. public final void refresh() throws BeansException, IllegalStateException {
  3. try {
  4. super.refresh();
  5. }
  6. catch (RuntimeException ex) {
  7. stopAndReleaseReactiveWebServer();
  8. throw ex;
  9. }
  10. }

三、ReactiveWebServerApplicationContext的onRefresh()

</>复制代码

  1. @Override
  2. protected void onRefresh() {
  3. super.onRefresh();
  4. try {
  5. createWebServer();
  6. }
  7. catch (Throwable ex) {
  8. throw new ApplicationContextException("Unable to start reactive web server",
  9. ex);
  10. }
  11. }

四、看到这里我们就找到入口方法了:createWebServer(),跟进去,找到NettyReactiveWebServerFactory中创建webserver

</>复制代码

  1. @Override
  2. public WebServer getWebServer(HttpHandler httpHandler) {
  3. HttpServer httpServer = createHttpServer();
  4. ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(
  5. httpHandler);
  6. return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
  7. }

看到ReactorHttpHandlerAdapter这个类想必特别亲切,在开篇说过是spring-cloud-gateway的入口,createHttpServer方法的细节暂时没有去学习了,后续有时间去深入了解下

结语

spring5的相关新特性也是在学习中,这一篇文章算是和springboot结合的入门吧,后续有时间再深入学习

更多文章可以访问博客:和公众号

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74417.html

相关文章

  • Spring Boot 2 快速教程:WebFlux 快速入门(二)

    摘要:响应式编程是基于异步和事件驱动的非阻塞程序,只是垂直通过在内启动少量线程扩展,而不是水平通过集群扩展。三特性常用的生产的特性如下响应式编程模型适用性内嵌容器组件还有对日志消息测试及扩展等支持。 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 02:WebFlux 快速入门实践 文章工程: JDK...

    gaara 评论0 收藏0
  • Spring Boot 2 快速教程:WebFlux 集成 Mongodb(四)

    摘要:在配置下上面启动的配置数据库名为账号密码也为。突出点是,即非阻塞的。四对象修改包里面的城市实体对象类。修改城市对象,代码如下城市实体类城市编号省份编号城市名称描述注解标记对应库表的主键或者唯一标识符。 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第104篇原创 文章工程: JDK...

    Corwien 评论0 收藏0
  • SpringBoot Kotlin 系列之HTMLWebFlux

    摘要:上一章我们提到过与,对于具体的介绍没说到,这一章我在这里简单介绍一下,既然提到和,那肯定得提到什么是响应式编程,什么是。 showImg(https://segmentfault.com/img/remote/1460000018819338?w=1024&h=500); 上一章我们提到过Mono 与 Flux,对于具体的介绍没说到,这一章我在这里简单介绍一下,既然提到Mono和Flu...

    crossoverJie 评论0 收藏0
  • Spring Boot 2 快速教程:WebFlux 集成 Thymeleaf(五)

    摘要:数据和信息是不可分离的,数据是信息的表达,信息是数据的内涵。数据本身没有意义,数据只有对实体行为产生影响时才成为信息。主要目标是为开发提供天然的模板,并且能在里面准确的显示。目前是自然更加推荐。 这是泥瓦匠的第105篇原创 文章工程: JDK 1.8 Maven 3.5.2 Spring Boot 2.1.3.RELEASE 工程名:springboot-webflux-4-thym...

    姘存按 评论0 收藏0
  • Spring Boot 2 快速教程:WebFlux Restful CRUD 实践(三)

    摘要:二结构这个工程会对城市进行管理实现操作。负责将持久层数据操作相关的封装组织,完成新增查询删除等操作。原因是,直接使用和是非阻塞写法,相当于回调方式。反应了是的好处集合了非阻塞异步。其实是的一个补充。可以发布类型的元素。 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第102篇原创 0...

    qujian 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<