Spring webflux,是在将要发布的Spring 5和Spring boot 2中提供的,结合非阻塞IO,Reactive 风格编程的异步非阻塞开发框架。
之前有一篇文章介绍了Vert.x,初次之外Java中还有Ratpack等以异步非阻塞编程为目标的项目。然而就目前来看,Spring Webflux将会是API设计最良好,最方便使用的一个。
Spring Webflux 介绍
Spring Webflux 是一个基于事件驱动的非阻塞实现,底层可以使用:
- Netty。
- 支持Servlet3.1 Non-Blocking Servlet标准的Web容器。具体的有Tomcat,Undertow,Jetty等。
默认使用的是Netty。毕竟Servlet整个生态都是针对阻塞IO的实现的,Async Servlet和Non-Blocking Servlet就是在Servlet标准中打的奇怪的格格不入的补丁。在性能上,Netty也有着不小的优势。
Spring Webflux 使用的Reactive System实现是Reactor,但是也支持使用RxJava,还有Java8 CompletableFuture。Reactor和RxJava2.0的实现接口基本一致,然而Reactor是基于Java8实现的,可以利用Java8中的许多既有实现(比如CompletableFuture,Stream等)。Reactor中最常使用的是Publisher的两个实现,Mono和Flux,Mono表示0或1,对应于RxJava中的MayBe,Completable,和Single;Flux表示1+数量,对应于RxJava中的Observable。
Spring Webflux 还提供了一个Netty实现的非阻塞WebClient,用来做Http 请求。
Spring Webflux 实例
我们这里完成一个和之前Vert.x一样功能的简单程序,使用HTTP请求网易新闻头条内容,然后抽取其中的文章标题,并以Json格式返回给客户端。项目使用Spring Boot开发。
@RestController
public class TopLinesHandler {
@Resource
private ObjectMapper mapper;
@GetMapping("/top_lines")
public Mono<Object> handleGetUserById() {
return getTopLines().map(this::extractTitles);
}
private Mono<String> getTopLines() {
WebClient webClient = WebClient.create("http://c.m.163.com");
return webClient.get().uri("/nc/article/headline/T1348647853363/0-20.html")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.flatMap(resp -> resp.bodyToMono(String.class));
}
private List<String> extractTitles(String jsonStr) {
JsonNode jsonNode;
try {
jsonNode = mapper.readTree(jsonStr);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
JsonNode articles = jsonNode.get("T1348647853363");
List<String> list = new ArrayList<>(articles.size());
for (int i = 0; i < articles.size(); i++) {
JsonNode article = articles.get(i);
String title = article.get("title").textValue();
list.add(title);
}
return list;
}
}
可以看到,在webflux中,也可以使用SpringMVC中定义的注解,这大大简化了路由,response处理等工作。
然后我们需要启动一个Spring Webflux应用程序:
@SpringBootApplication
public class WebfluxApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(WebfluxApplication.class)
.run(args);
}
}
还是熟悉的配方,还是熟悉的味道。
当然,对于JDBC这种只有同步阻塞实现的,还是需要wrap到额外的线程池,以避免阻塞EventLoop,目前Spring Webflux还没有对这些做封装,需要的话只能自己动手了。
现在已经可以使用https://start.spring.io/方便的创建自己的Spring Webflux项目,注意SpringBoot要选2.0版本,Dependencies里加上Webflux。