异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用

上两节课我们做了两个非常简单的方式 实现异步请求 并且做个简单的页面(test1.html) 测试异步提交和同步提交的区别
这节课我们学习异步请求的第三种方式
上两节课学到了

异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第1张图片
image.png

这节课学下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第2张图片
image.png

这节课我们首先看下DeferredResult如何使用
来到官网 https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-async-deferredresult
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第3张图片
image.png

官方给我们一段示例如上
上节课我们做的异步代码 返回的是Callable
通过官网可知使用DeferredResult处理异步过程 要返回DeferredResult 并且实例化一个DeferredResult
然后可以在其他线程里对实例化的deferredResult 结果进行赋值
下面我们看下其他线程如何配合 如果我们写些模拟代码 上节课我们通过线程的等待来做些模拟代码(这看起来没什么意义)
所以这节课我们结合实际场景 看下如何使用
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第4张图片
image.png

网站和我们的消息队列(这节课使用redis演示下,使用它来进行交互和我们数据处理的基本流程)
首先按照上图编号来看
有个做的网站A(当用户提交数据过来时假设并发很高,那么一般来说会把数据放入消息队列),在外部一定有个消费者程序(死循环程序)部署在其他服务器上 专门来对消息队列进行读取 读取到消息后,就进行处理(更新数据库做些统计更新等等)做完之后把处理好的结果放入消息队列 这个时候网站本身也是个消费者(专门有线程处理)那么这个网站 比如用户提交一个信息后,它需要到消息队列看下是否完成 如果没有完成 会等待(可以设置一定的超时时间)如果完成了 就把数据返回给我们的请求线程
下面我们做过案例(结合redis理解上面的过程)spring和redis或其他类库进行交互调用
在NewsController中添加官方的DeferredResult使用代码如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第5张图片
image.png

修改下test1.html
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第6张图片
image.png

添加如上(存在localhost:8999/test1.html)
编译发布代码
浏览器访问 http://localhost:8999/test1.html
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第7张图片
image.png

点击async_submit(Deffered)按钮 (异步提交)
结果如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第8张图片
image.png

从上面结果好像看不出任何异步的过程
下面我们进入今天重点内容
首先看下Spring如何和redis交互
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第9张图片
image.png

我们来到 https://projects.spring.io/spring-data-redis/官网(Spring封装好的操作redis的库 Spring data redis)
其内部包含个Jedis库 来到Jedis的github地址 https://github.com/xetorthio/jedis 它可以赤裸裸的连接redis 但是一些方法包括一些函数分类并没有Spring data redis分的比较业务化
我们这节课用下Spring data redis
下面看下使用步骤
根据官方提示
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第10张图片
image.png

首先在pom.xml中加入依赖

org.springframework.data
spring-data-redis
2.0.5.RELEASE

接下来来到Spring data redis 详细文档 查看下 使用所需依赖 https://docs.spring.io/spring-data/redis/docs/2.0.5.RELEASE/reference/html/
点击目录的Requirements
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第11张图片
image.png

异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第12张图片
image.png

可以看见对JDK和Spring framework等有一定的要求
因为redis里面使用到了连接池 并且依赖jedis库
下面加入这两个依赖

org.apache.commons
commons-pool2
2.0


redis.clients
jedis
2.9.0
jar
compile

配置好了之后
我们对redis里面订阅发布功能(就是使用redis来完成一个简单的消息队列)
redis官方里有个Pub/Sub(发布/订阅功能)
官方说明如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第13张图片
image.png

下面我们来模拟如下需求
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第14张图片
image.png

比如我们通过发布 在客户端可以订阅这个消息 订阅好之后 如果我们一旦有新消息 那么我们多客户端都可以同时得到这个消息来对它进行处理
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第15张图片
image.png

一旦有消息 只要订阅过该频道 都可以获取这个消息
首先打开一个cmd客户端
进入到redis安装目录
启动一个redis服务 命令结果如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第16张图片
image.png

然后我们在启动一个cmd客户端
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第17张图片
image.png

然后我们再来一个
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第18张图片
image.png

我们共启动了3个redis服务(连接到服务器里共有3个客户端)
假设有个频道叫做users(自定义的频道)
首先订阅subscribe users(可以看做消费者)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第19张图片
image.png

这时会等待我们频道发送消息
接下来在另外一个cmd窗口同样订阅如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第20张图片
image.png

接下来假设还有最后一个cmd客户端窗口认为是个发布者(可以发布一个消息)
执行命令如下 publish users abc(abc为自己起的名字)
如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第21张图片
image.png

其中2表示有2个客户端进行接收消息
然后观看另外两个cmd窗口变化
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第22张图片
image.png

同时会出现3个消息 第一个为消息类型。第二个为频道名,第三个为真实值。
同样我们在发布端在发布一条消息
publish users hello
如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第23张图片
image.png

观看订阅端窗口接收消息如下(立即出现 只要发布了消息)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第24张图片
image.png

这个应用到我们的java里面 肯定也是通过java程序来执行publish 专门有个死循环程序进行订阅 我们网站本身也可以订阅
在订阅的过程中一定是单开个线程来执行这个订阅过程的 如果有外部发布消息 那么我们订阅的这个线程一定可以得到这个消息
然后做处理
接下来首先关掉两个cmd客户端窗口(执行subscribe users命令的窗口 不是发布窗口)
而把publish users hello这个cmd窗口认为死循环程序(做完处理后 执行publish)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第25张图片
image.png

接下来把网站同时作为订阅端
我们在UserController中的update方法中执行发布后(也就是下面这个方法),发布消息后。然后等待后端处理
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第26张图片
image.png

下面看下用java程序如何做
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第27张图片
image.png

如何创建内容以及在Spring中如何配置 (如何操作redis)
首先看官网 https://docs.spring.io/spring-data/redis/docs/2.0.5.RELEASE/reference/html/
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第28张图片
image.png

首先做个连接工厂(连接器)
可以手工写代码或者spring配置文件的方式(通过IOC容器进行控制 推荐这种方式)
所以我们首先在context-spring配置文件中加入如下
image.png

可以发现代码报红色了 是因为缺少命名空间
在context-spring中beans节点上加入如下命名空间(根据官网看到的)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第29张图片
image.png

再看下我们添加的依赖报错消失了
image.png

所加命名空间在官网如下可看见
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第30张图片
image.png

接下来看这页内容如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第31张图片
image.png

接下来加入RedisTemplate(这节课我们没用到,但以后肯定会用到) 所以这里先加入
context-spring中添加如下
这是一个spring data redis帮我们封装好的操作工具类
image.png

接下来就可以在代码里引用配置的这个bean了
在UsersController中引用配置好的bean
首先在UsersController类上打入@AutoWired注解(自动装配)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第32张图片
image.png

引入redisTemplate对象
接下来看下如何进行监听(其实网站在启动的时候就需要它实现监听 因为一旦我们有消息发送过来,它必定马上得到消息后进行进一步的处理)
来到官网(5.9章节)可以看见如下 一个是发送 一个是接收
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第33张图片
image.png

这节课我们要演示的是异步请求 做个简单的配置
配置内容如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第34张图片
image.png

首先定义一个redis-listener监听器(官方如下)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第35张图片
image.png

下面我们把配置加入到context-spring中 添加如下(这个是我们默认的ConnectionFactory 我们这里需要指定成我们配置的jedisConnectionFactory)
image.png

修改后添加如下
image.png

其中container内容包含的就是监听的内容(是用来监听users频道的 也就是我们cmd中发布的信息)
定义好监听器之后 他就可以帮我们实现相关的一些监听 但是我们需要去实现一旦监听到消息后 应该如何做(这个是需要我们执行的)
里面的属性意思为topic就是我们的频道 因此我们这里需要改为users
因为我们发布的频道为users
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第36张图片
image.png

所以在此修改context-spring如下
image.png

剩下两个属性 看我们具体操作
首先在com.jtthink包下面创建个包叫redis
目录如下
里面写个IMsgListener接口
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第37张图片
image.png

代码如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第38张图片
image.png

接下来在redis包下面创建个实现类MsgListener
继承IMsgListener接口实现handleMessage方法
代码如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第39张图片
image.png

接下来需要在Spring配置文件中加入一个bean
打开context-spring.xml文件
image.png

修改如上 加入了一个bean是我们定义的实现类 然后把id绑定给redis-listener中的ref(将二者进行关联)
这时网站启动 自动会进行监听 然后一旦得到消息 会交给MsgListener处理
接下来写好代码 重新发布下
发布完成后来到cmd客户端窗口发布一条消息
publish users javaabc如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第40张图片
image.png

其中的1代表有一个客户端得到了消息
同时这时我们的控制台输出了javaabc如下(我们已经实现了监听 并且一旦得到消息后 可以来处理 是一个单独的线程处理的 并不是我们的请求线程)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第41张图片
image.png

我们在发布一条消息
publish users hello
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第42张图片
image.png

控制台
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第43张图片
image.png

这样的结果有什么意义呢 和我们之前的请求有什么关系呢
下面进行关联
接下来改造下异步的代码(update函数 UsersController中)
首先注释掉一句
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第44张图片
image.png

接下来来到MsgListener定义一个属性
并生成get和set方法
代码如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第45张图片
image.png

这时我们在UsersController中就可以得到deferredResult的值
由于我们的监听器是在context-spring配置文件中配置的 (使用IOC容器自动加载)
所以我们要在UsersController中打入自动装配注解 引入MsgListener类
代码如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第46张图片
image.png

接下来需要对update方法进行修改(UsersController中)
代码如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第47张图片
image.png

由于我们把deferredResult传给了msgListener
也就是说只有其他线程里设置setResult的时候才会触发(把我们当前的数据传给我们请求主线程)才会执行update方法
deferredResult创建后需要在当前线程或者其他线程进行setResult设置,否则里面没值
接下来重新发布代码
首先我先点击async_submit(deffred)按钮(会请求我们UsersController中的update异步方法)
过了5s中弹出如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第48张图片
image.png

因为我们在没有在任何线程里执行setResult方法并把其返回出来
接下来打开cmd 开启一个redis客户端窗口如下
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第49张图片
image.png

我们在次点击async_submit(deffred)按钮 然后立马在redis客户端中发布一条消息(5s内发布)
操作步骤先点击按钮 在5s内在cmd客户端窗口执行publish users hello (发布消息)
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第50张图片
image.png

cmd窗口出现如下 说明有一个客户端连接
看test1.html页面内容
异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用_第51张图片
image.png

监听到了我们的users频道 并且立马弹出内容hello不会超时
其中这里面完整过程如下
首先我们UsersController中的(update)方法完成对数据进行更新,一旦得到数据后,在这个方法里面可以直接调用消息队列
比如我们publish(发布)的频道(users)这时我们在users这个消息队列里面就会有另外一个死循环程序在监听(users)频道,得到消息后,就会对数据进行处理,然后把数据放入另一个渠道(b)里面 我们所监听的内容就是监听这个b 一旦b里面有数据了 我们立马就返回 这就是基本的过程

你可能感兴趣的:(异步请求入门,使用DeferredResult,结合Redis发布订阅功能体现异步请求的作用)