java 响应式 服务 框架 java响应式编程 业务场景

您所在的位置:网站首页 spring5响应式编程 java 响应式 服务 框架 java响应式编程 业务场景

java 响应式 服务 框架 java响应式编程 业务场景

2023-06-15 12:22| 来源: 网络整理| 查看: 265

最近接触到响应式编程的概念,简单了解了一下在java中的响应式编程。响应式编程是一个专注于数据流和变化传递的异步编程范式。

响应式编程是一种编程概念,在很多编程语言中都有应用。其中,在Java中,我们比较熟悉的有RxJava,有关RxJava的介绍,已经有大神写出比较完善的介绍: 深入浅出RxJava(一:基础篇) 深入浅出RxJava(二:操作符) 深入浅出RxJava三–响应式的好处

以上三篇博客已经初步介绍RxJava的使用方式以及一些应用场景,在此不再多介绍如何使用,这里尝试简单分析一下他的设计原理以及实现方式。

响应式编程是观察者模式的扩展,RxJava中的实现也是如此。下面是一个观察者模式demo。

public class ReactiveDemo { public static void main(String[] args){ //可观察对象 MyObservable observable = new MyObservable(); //添加观察者 observable.addObserver((o, arg) -> { Util.println("观察者1处理事件:" + arg.toString()); }); observable.addObserver((o, arg) -> { Util.println("观察者2处理事件:" + arg.toString()); }); observable.addObserver((o, arg) -> { Util.println("观察者3处理事件:" + arg.toString()); }); //发布事件通知观察者 observable.setChanged(); observable.notifyObservers("事件@@"); } static class MyObservable extends Observable{ @Override public void setChanged(){ super.setChanged(); } } }

执行输出

2018-06-23 18:16:43:993[main] 观察者3处理事件:事件@@ 2018-06-23 18:16:44:015[main] 观察者2处理事件:事件@@ 2018-06-23 18:16:44:015[main] 观察者1处理事件:事件@@

从输出可以看出,代码的执行顺序并非按照我们的代码顺序执行,而是反过来,通过debug可以进一步看到,在添加观察者回调函数时,回调函数代码没有执行(这不是废话嘛0.0),知道被观察者发布事件通知观察者处理事件时才执行回调函数,并且都是在main线程中同步执行。这种方式可以称为同步非阻塞的响应式编程。既然有同步式的非阻塞,那就有异步非阻塞的响应式编程,在Java中的Swing就是一个很好的例子。 下面看一下我们最常见的一个swing例子。

public class SwingFrame { public static void main(String[] args) { JFrame jFrame = new JFrame(); jFrame.setVisible(true); jFrame.setBounds(200,200,400,400); jFrame.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); CommonUtil.println("鼠标点击事件"); } }); jFrame.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { super.focusGained(e); CommonUtil.println("焦点事件"); } }); } }

执行程序,看看鼠标点击事件和焦点事件。

2018-06-24 07:53:20:753[AWT-EventQueue-0] 焦点事件 2018-06-24 07:53:25:216[AWT-EventQueue-0] 鼠标点击事件 2018-06-24 07:53:27:849[AWT-EventQueue-0] 焦点事件 2018-06-24 07:53:30:416[AWT-EventQueue-0] 鼠标点击事件

尝试了几次,发现在swing的事件响应处理并不是在main线程里面进行处理的,鼠标点击和焦点事件处理都是在一个叫AWT-EventQueue-0的线程中进行处理,可以看见这种异步处理的方式有别于上面的观察者模式。这里对于事件的响应更加类似于一种对事件进行拉取的方式,我们点击窗体,发现打印鼠标事件是有延迟的,原因就是这里对于事件的获取是采用另起一个线程轮询策略,监听到对应的事件之后委托给对应的事件处理器(回调函数)进行处理,这种方式叫异步非阻塞。

基于以上概念延伸出来的Reactive web,实现思路大致类似。我们了解一下原生servlet的Reactive web是怎么实现的。下面是一段网上找的描述。

在服务器的并发请求数量比较大的时候,会产生很多的servlet线程(这些servlet线程在servlet容器的线程池中维护),如果每个请求需要耗费的时间比较长(比如,执行了一些IO的处理等),在之前的非异步的servlet中,这些servlet线程将会阻塞,严重耗费服务器的资源.而在servlet3.0中首次出现的异步servlet,通过一个单独的新的线程来执行这些比较耗时的任务(也可以把这些任务放到一个自己维护的线程池里),servlet线程立即返回servlet容器的servlet池以便响应其他请求,这样,在降低了系统的资源消耗的同时,也会提升系统的吞吐量

java 响应式 服务 框架 java响应式编程 业务场景_ide

上面这种异步处理请求的方式是我们开发中常用的思路,在netty中的selector,worker概念和这个类似,下面看一下servlet中如何实现。

@WebServlet(urlPatterns = "/asyncServlet", asyncSupported = true) public class AsyncServlet extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { CommonUtil.println("开始执行servlet"); //开启异步上下文 AsyncContext asyncContext = request.startAsync(); //异步上下文设置回调函数(监听器) asyncContext.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent asyncEvent) throws IOException { ServletResponse response1 = asyncEvent.getSuppliedResponse(); response1.setContentType("text/html;"); response1.getWriter().println("complete回调函数返回输出"); CommonUtil.println("complete回调函数完成"); } @Override public void onTimeout(AsyncEvent asyncEvent) throws IOException { } @Override public void onError(AsyncEvent asyncEvent) throws IOException { } @Override public void onStartAsync(AsyncEvent asyncEvent) throws IOException { } }); //开启新的工作线程,释放servlet处理请求线程,工作完后回调异步上下文的监听器 new Thread(() -> { try { ServletResponse response1 = asyncContext.getResponse(); response1.setContentType("text/html;charset=UTF-8"); response1.getWriter().print("异步工作线程返回输出"); //出发回调函数onComplete() CommonUtil.println("工作线程完成"); asyncContext.complete(); } catch (IOException e) { e.printStackTrace(); } }).start(); CommonUtil.println("释放servlet线程"); } }

执行程序并且访问,输出

2018-06-24 09:37:18:581[http-nio-8080-exec-1] 开始执行servlet 2018-06-24 09:37:18:584[http-nio-8080-exec-1] 释放servlet线程 2018-06-24 09:37:18:585[Thread-13] 工作线程完成 2018-06-24 09:37:18:587[http-nio-8080-exec-2] complete回调函数完成

明显可以看到接收请求线程,工作线程和回调函数线程都是不同的线程,这里面的回调方式,我猜测跟swing的事件处理方式可能一样,有专门线程进行轮询(没验证。。)。上面代码可以看出实现思路是开辟一个工作线程处理io等,然后触发上下文监听器回调函数,基本思路是这样实现。

这里的处理方式的好处是, 正如上面所说的,”servlet线程立即返回servlet容器的servlet池以便响应其他请求,这样,在降低了系统的资源消耗的同时,也会提升系统的吞吐量”。

ractive的编程方式,不一定能提升程序性能,但是它希望做到的是用少量线程和内存提升伸缩性,及时响应新请求。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3