Webflux快速⼊门
  SpringWebflux是SpringFramework5.0添加的新功能,WebFlux本⾝追随当下最⽕的Reactive Programming⽽诞⽣的框架,那么本篇就来简述⼀下这个框架到底是做什么的
⼀、关于WebFlux
  我们知道传统的Web框架,⽐如说:struts2,springmvc等都是基于Servlet API与Servlet容器基础之上运⾏的,在Servlet3.1之后才有了异步⾮阻塞的⽀持。⽽WebFlux是⼀个典型⾮阻塞异步的框架,它的核⼼是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运⾏在诸如Netty,Undertow及⽀持Servlet3.1的容器上,因此它的运⾏环境的可选择⾏要⽐传统web框架多的多。
  根据官⽅的说法,webflux主要在如下两⽅⾯体现出独有的优势:
  1)⾮阻塞式
    其实在servlet3.1提供了⾮阻塞的API,WebFlux提供了⼀种⽐其更完美的解决⽅案。使⽤⾮阻塞的⽅式可以利⽤较⼩的线程或硬件资源来处理并发进⽽提⾼其可伸缩性
  2) 函数式编程端点
    ⽼⽣常谈的编程⽅式了,Spring5必须让你使⽤java8,那么函数式编程就是java8重要的特点之⼀,⽽WebFlux⽀持函数式编程来定义路由端点处理请求。
⼆、SpringMVC与SpringWebFlux
我们先来看官⽹的⼀张图:
  它们都可以⽤注解式编程模型,都可以运⾏在tomcat,jetty,undertow等servlet容器当中。但是SpringMVC采⽤命令式编程⽅式,代码⼀句⼀句的执⾏,这样更有利于理解与调试,⽽WebFlux则是基于异步响应式编程,对于初次接触的码农们来说会不习惯。对于这两种框架官⽅给出的建议是:
  1)如果原先使⽤⽤SpringMVC好好的话,则没必要迁移。因为命令式编程是编写、理解和调试代码的最简单⽅法。因为⽼项⽬的类库与代码都是基于阻塞式的。
  2)如果你的团队打算使⽤⾮阻塞式web框架,WebFlux确实是⼀个可考虑的技术路线,⽽且它⽀持类似于SpringMvc的Annotation的⽅式实现编程模式,也可以在微服务架构中让WebMvc与WebFlux共⽤Controller,切换使⽤的成本相当⼩
  3)在SpringMVC项⽬⾥如果需要调⽤远程服务的话,你不妨考虑⼀下使⽤WebClient,⽽且⽅法的返回值可以考虑使⽤Reactive Type 类型的,当每个调⽤的延迟时间越长,或者调⽤之间的相互依赖程度越⾼,其好处就越⼤
  我个⼈意见是:官⽹明确指出,SpringWebFlux并不是让你的程序运⾏的更快(相对于SpringMVC来说),⽽是在有限的资源下提⾼系统的伸缩性,因此当你对响应式编程⾮常熟练的情况下并将其应⽤于新的系统中,还是值得考虑的,否则还是⽼⽼实实的使⽤WebMVC吧
三、Reactive Spring Web
  在这⾥定义了最基本的服务端接⼝:HttpHandler和WebHandler
  HttpHandler
  HttpHandler定义了最基本的处理Http请求⾏为,这个接⼝主要作⽤是处理Http请求并将结果做出响应,下⾯这个表格是说明了Server API的使⽤⽅式及何种⽅式进⾏响应式流⽀持的:
Server name Server API used Reactive Streams support
Netty Netty API
Undertow Undertow API spring-web: Undertow to Reactive Streams bridge
Tomcat Servlet 3.1 non-blocking I/O; Tomcat API to read and write
ByteBuffers vs byte[]
spring-web: Servlet 3.1 non-blocking I/O to Reactive
Streams bridge
Jetty Servlet 3.1 non-blocking I/O; Jetty API to write ByteBuffers vs
byte[]
spring-web: Servlet 3.1 non-blocking I/O to Reactive
Streams bridge
Servlet 3.1 container Servlet 3.1 non-blocking I/O
spring-web: Servlet 3.1 non-blocking I/O to Reactive
Streams bridge
  WebHandler
  WebHandler定义了Web请求必要⼀些处理⾏为,⼤家不妨想想看:WebFlux已经脱离了Servlet API,那么使⽤WebFlux时遇到会话机制怎么办,想要对请求过滤处理怎么办或者想要处理静态资源怎么办等等,那么WebHandler就是做这个事情的。其实在HttpHandler的基本实现类通过适配器模式及装饰模式也间接的实现了WebHandler接⼝:
  WebHandler常见的实现类,我在这⾥列举⼀下:
  WebHandlerDecorator:WebHandler的装饰器,利⽤装饰模式实现相关功能的扩展
  HttpWebHandlerAdapter: 进⾏Http请求处理,同时也是HttpHandler的实现类
  FilteringWebHandler:通过WebFilter进⾏过滤处理的类,类似于Servlet中的Filter
  ExceptionHandlingWebHandler: 针对于异常的处理类
  ResourceWebHandler:⽤于静态资源请求的处理类
  DispatcherHandler:请求的总控制器,类似于WebMVC中的DispatcherServlet
reactor框架介绍四、实现WebFlux⽰例
建⽴SpringBoot项⽬,注意SpringBoot版本必须为2.0.0+,在adle配置⽂件⾥写:
compile('org.springframework.boot:spring-boot-starter-webflux')
基于Annotated Controller⽅式实现
WebFluxConfig配置:
package com.hzgj.framework.study.active;
import t.ApplicationContext;
import t.annotation.Bean;
import t.annotation.ComponentScan;
import t.annotation.Configuration;
import org.active.DispatcherHandler;
import org.fig.EnableWebFlux;
import org.fig.WebFluxConfigurer;
@Configuration
@ComponentScan
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer {
@Bean
public WebHandler webHandler(ApplicationContext applicationContext) {
DispatcherHandler dispatcherHandler = new DispatcherHandler(applicationContext);
return dispatcherHandler;
}
}
在这⾥我们创建⼀个WebHandler并使⽤@EnableWebFlux打开相关功能。我们可以发现与SpringMVC的WebConfig配置真的好像
Controller:
package com.hzgj.framework.study.ller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@GetMapping("/index")
public String index() {
return "index";
}
}
  在这⾥与SpringMVC定义的Controller⽆异
Main⽅法:
package com.hzgj.framework.study.active;
import t.annotation.AnnotationConfigApplicationContext;
import org.springframework.active.HttpHandler;
import org.springframework.active.ReactorHttpHandlerAdapter;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.ipcty.http.server.HttpServer;
import java.io.IOException;
/**
* 基于Reactor Netty实现WebFlux服务
* @author chen.nie
* @date 2018/7/13
**/
public class SpringWebfluxApplication {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebFluxConfig.class);
//通过ApplicationContext创建HttpHandler
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();
ReactorHttpHandlerAdapter httpHandlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
ad();
}
}
  程序启动成功后即可通过localhost:8080/index拿到对应结果
函数式编程⽅式
  使⽤这种⽅式请先了解Java8提供的函数式编程特性。那么我们先编写⼀个简单的Handler
package com.hzgj.framework.study.active.handler;
import org.springframework.beans.BeanUtils;
import org.active.function.server.ServerRequest;
import org.active.function.server.ServerResponse;
publisher.Mono;
import static org.springframework.http.MediaType.*;
import static org.active.function.BodyInserters.fromObject;
import static org.active.function.server.ServerResponse.ok;
/**
* 类似于Controller,处理⽤户请求的真实逻辑
*/
public class StudentHandler {
public static Mono<ServerResponse> selectStudent(ServerRequest request) {
Student studentBody = new Student();
request.bodyToMono(Student.class).subscribe(student -> pyProperties(student, studentBody));
return ok().contentType(APPLICATION_JSON_UTF8).body(fromObject(studentBody));
}
public static Mono<ServerResponse> insertStudent(ServerRequest request){
return ok().contentType(TEXT_PLAIN).body(fromObject("success"));
}
private static class Student {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
  这个Handler类似于Controller的作⽤,在这⾥的返回值均为Mono类型,其中ServerRequest和ServerResponse,⼤家可以先理解为WebFlux替代ServletRequest与ServletResponse对象的,⽽且这些类能够⽀持异步。
  Main⽅法⾥我们创建的HttpHandler的⽅式需要进⾏改变⼀下,同样⽤函数式⽅式进⾏编写:
package com.hzgj.framework.study.active;
import com.hzgj.framework.study.active.handler.StudentHandler;
import org.springframework.http.MediaType;
import org.springframework.active.HttpHandler;
import org.springframework.active.ReactorHttpHandlerAdapter;
import reactor.ipcty.http.server.HttpServer;
import java.io.IOException;
import static org.active.function.server.RequestPredicates.*;
import static org.active.function.ute;
import static org.active.function.HttpHandler;
public class FunctionRouteApplication {
public static void main(String[] args) throws IOException {
HttpHandler httpHandler = toHttpHandler(
route(POST("/selectStudent").and(accept(MediaType.APPLICATION_JSON_UTF8)), StudentHandler::selectStudent).
and(route(GET("/saveStudent"), StudentHandler::insertStudent)));
ReactorHttpHandlerAdapter httpHandlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
ad();
}
}
启动成功后,我们⽤postman测试⼀下
此时我们可以看到使⽤函数式编程创建路由端点,也可以实现同样的功能。
集成Thymeleaf
@Configuration
@EnableWebFlux
@ComponentScan
public class WebFluxConfig implements WebFluxConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
@Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
@Bean
public SpringWebFluxTemplateEngine templateEngine() {
SpringWebFluxTemplateEngine templateEngine = new SpringWebFluxTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
@Bean
public ThymeleafReactiveViewResolver viewResolver() {
ThymeleafReactiveViewResolver viewResolver = new ThymeleafReactiveViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.viewResolver(viewResolver());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
在这⾥注意以下,在webflux中不⽀持直接创建Bean的⽅式配置视图解析器,我们可以参考下⾯的源码:WebFluxConfiguraitonSupport @Bean
public ViewResolutionResultHandler viewResolutionResultHandler() {
ViewResolverRegistry registry = getViewResolverRegistry();
List<ViewResolver> resolvers = ViewResolvers();
ViewResolutionResultHandler handler = new ViewResolutionResultHandler(
resolvers, webFluxContentTypeResolver(), webFluxAdapterRegistry());

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。