本文住主要分析SpringFlux的响应式与Servelet阻塞式有优缺点
1、关键词
响应式:异步、观察、高吞吐量、弹性、消息驱动、符合利用现代处理器利用多核、阻塞代码转向非阻塞代码、反应式代码用更少的资源做更多的工作
基于异步的开发模式是相对于同步的开发模式而言。结合具体场景而言,所谓同步是指程序使用者发出请求后,无法使用其他功能而只能等待直到该请求程序处理结果返回;而异步是指程序使用者发出某个请求后,不用等待该请求的程序处理结果返回,而是可正常使用其他功能,待使用其他功能后回过头来可正常查看原有请求的程序处理结果。无论作为开发者还是程序使用者,都不希望程序处理总是处于等待、在等待的状态,通过异步编程模式,程序使用者可以在明知某个任务会耗时较长的情况下,无等待的使用其他功能,从而获得良好的使用体验
SpringMVC 方式实现,同步阻塞的方式,基于 SpringMVC+Servlet+Tomcat
SpringWebflux 方式实现,异步非阻塞 方式,基于 SpringWebflux+Reactor+Netty
第一 两个框架都可以使用注解方式,都运行在 Tomcat 等容器中
第二 SpringMVC 采用命令式编程,Webflux 采用异步响应式编程
无论是从底层数据库,向上到达服务层,最后到 Web 服务层,抑或是在这个流程中所包含的任意中间层组件,整个数据传递链路都应该是采用事件驱动的方式来进行运作的。我们就可以不同步调用方式来处理数据,而是由处于数据库上游的各层组件自动来执行事件。这就是响应式编程的核心特点
相较传统开发所普遍采用的“拉”模式,在响应式编程下,基于事件的触发和订阅机制,这就形成了一种类似“推”的工作方式。这种工作方式的优势就在于,生成事件和消费事件的过程是异步执行的,所以线程的生命周期都很短,也就意味着资源之间的竞争关系较少,服务器的响应能力也就越高。
2、Reactor框架
1.传统的方式
String name = "Simon";
String capitalName = name.toUpperCase();
String greeting = "Hello " + capitalName + "!";
System.out.println(greeting );
以上是命令式编程的写法,有两个特征:
- 串行化
- 独占线程
2.Reactor
//单数据
Mono<String> simon = Mono.just("①")
.map(s -> s.toUpperCase())
.map(s -> "Hello " + s + "!");
System.out.println("执行其他业务");
simon.subscribe(gn -> System.out.println(gn));
以上是用Reactor的写法,有点像Stream流一样,在处理字符串哪些后,只有调用subscribe()方法才会去最终处理
调用 just 或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生的
//多数据
Flux<String> filter = Flux.just("①", "②", "③", "④", "⑤", "⑥")
.map(s -> s.toLowerCase())
.map(s -> "Hello " + s + "!")
.distinct()//去重
.filter(s -> !s.equals("Hello ③!"));//过滤
System.out.println("执行其他业务");
filter.subscribe(s -> System.out.println(s));
以上是有多个数据的写法用的是Flux,Mono是单数据的;
3、Spring Flux
Client代码
import com.lsy.reactor.pojo.User;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
public class Client {
public static void main(String[] args) {
//调用服务器地址
WebClient webClient = WebClient.create("http://127.0.0.1:5794");
//根据id查询
String id = "1";
User userresult = webClient.get().uri("/users/{id}", id)
.accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class)
.block();
System.out.println(userresult.getName());
//查询所有
Flux<User> results = webClient.get().uri("/users")
.accept(MediaType.APPLICATION_JSON).retrieve().bodyToFlux(User.class);
results.map(stu -> stu.getName())
.buffer().doOnNext(System.out::println).blockFirst();
}
}
Server代码
```java
import com.lsy.reactor.handler.UserHandler;
import com.lsy.reactor.service.UserService;
import com.lsy.reactor.service.UserServiceImpl;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
public class Server {
public static void main(String[] args) throws Exception{
Server server = new Server();
server.createReactorServer();
System.out.println("enter to exit");
System.in.read();
}
//1 创建Router路由
public RouterFunction<ServerResponse> routingFunction() {
//创建hanler对象
UserService userService = new UserServiceImpl();
UserHandler handler = new UserHandler(userService);
//设置路由
return RouterFunctions.route(
GET("/users/{id}").and(accept(APPLICATION_JSON)),handler::getUserById)
.andRoute(GET("/users").and(accept(APPLICATION_JSON)),handler::getAllUsers);
}
//2 创建服务器完成适配
public void createReactorServer() {
//路由和handler适配
RouterFunction<ServerResponse> route = routingFunction();
HttpHandler httpHandler = toHttpHandler(route);
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
//创建服务器
HttpServer httpServer = HttpServer.create();
httpServer.handle(adapter).bindNow();
}
}
响应式需要双方的支持,目前Mysql不支持,Redis已经支持了。