SpringBoot如何实现长轮询操作?
- 内容介绍
- 文章标签
- 相关推荐
本文共计593个文字,预计阅读时间需要3分钟。
Spring Boot 长轮询实现,基于 @EnableAsync、@Sync、@SpringBootApplication
java@EnableAsync@Sync@SpringBootApplicationpublic class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }
@RequestMapping(/async) public void asyncRequest() { // 异步处理逻辑 }}
springboot 长轮询实现
基于 @EnableAsync , @Sync
@SpringBootApplication @EnableAsync public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
@RequestMapping("/async") @RestController public class AsyncRequestDemo { @Autowired private AsyncRequestService asyncRequestService; @GetMapping("/value") public String getValue() { String msg = null; Future<String> result = null; try{ result = asyncRequestService.getValue(); msg = result.get(10, TimeUnit.SECONDS); }catch (Exception e){ e.printStackTrace(); }finally { if (result != null){ result.cancel(true); } } return msg; } @PostMapping("/value") public void postValue(String msg) { asyncRequestService.postValue(msg); } }
@Service public class AsyncRequestService { private String msg = null; @Async public Future<String> getValue() throws InterruptedException { while (true){ synchronized (this){ if (msg != null){ String resultMsg = msg; msg = null; return new AsyncResult(resultMsg); } } Thread.sleep(100); } } public synchronized void postValue(String msg) { this.msg = msg; } }
备注
@EnableAsync 开启异步
@Sync 标记异步方法
Future 用于接收异步返回值
result.get(10, TimeUnit.SECONDS); 阻塞,超时获取结果
Future.cancel() 中断线程
补充:通过spring提供的DeferredResult实现长轮询服务端推送消息
DeferredResult字面意思就是推迟结果,是在servlet3.0以后引入了异步请求之后,spring封装了一下提供了相应的支持,也是一个很老的特性了。DeferredResult可以允许容器线程快速释放以便可以接受更多的请求提升吞吐量,让真正的业务逻辑在其他的工作线程中去完成。
最近再看apollo配置中心的实现原理,apollo的发布配置推送变更消息就是用DeferredResult实现的,apollo客户端会像服务端发送长轮训localhost:8080/watch/mynamespace,请求会挂起,60秒后,DeferredResult超时,客户端正常收到了304状态码,表明在这个期间配置没有变更过。
然后我们在模拟配置变更的情况,再次发起请求localhost:8080/watch/mynamespace,等待个10秒钟(不要超过60秒),然后调用localhost:8080/publish/mynamespace,发布配置变更。这时postman会立刻收到response响应结果:
mynamespace changed:1538880050147
表明在轮训期间有配置变更过。
这里我们用了一个MultiMap来存放所有轮训的请求,Key对应的是namespace,value对应的是所有watch这个namespace变更的异步请求DeferredResult,需要注意的是:在DeferredResult完成的时候记得移除MultiMap中相应的key,避免内存溢出请求。
采用这种长轮询的好处是,相比一直循环请求服务器,实例一多的话会对服务器产生很大的压力,http长轮询的方式会在服务器变更的时候主动推送给客户端,其他时间客户端是挂起请求的,这样同时满足了性能和实时性。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持易盾网络。如有错误或未考虑完全的地方,望不吝赐教。
本文共计593个文字,预计阅读时间需要3分钟。
Spring Boot 长轮询实现,基于 @EnableAsync、@Sync、@SpringBootApplication
java@EnableAsync@Sync@SpringBootApplicationpublic class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }
@RequestMapping(/async) public void asyncRequest() { // 异步处理逻辑 }}
springboot 长轮询实现
基于 @EnableAsync , @Sync
@SpringBootApplication @EnableAsync public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
@RequestMapping("/async") @RestController public class AsyncRequestDemo { @Autowired private AsyncRequestService asyncRequestService; @GetMapping("/value") public String getValue() { String msg = null; Future<String> result = null; try{ result = asyncRequestService.getValue(); msg = result.get(10, TimeUnit.SECONDS); }catch (Exception e){ e.printStackTrace(); }finally { if (result != null){ result.cancel(true); } } return msg; } @PostMapping("/value") public void postValue(String msg) { asyncRequestService.postValue(msg); } }
@Service public class AsyncRequestService { private String msg = null; @Async public Future<String> getValue() throws InterruptedException { while (true){ synchronized (this){ if (msg != null){ String resultMsg = msg; msg = null; return new AsyncResult(resultMsg); } } Thread.sleep(100); } } public synchronized void postValue(String msg) { this.msg = msg; } }
备注
@EnableAsync 开启异步
@Sync 标记异步方法
Future 用于接收异步返回值
result.get(10, TimeUnit.SECONDS); 阻塞,超时获取结果
Future.cancel() 中断线程
补充:通过spring提供的DeferredResult实现长轮询服务端推送消息
DeferredResult字面意思就是推迟结果,是在servlet3.0以后引入了异步请求之后,spring封装了一下提供了相应的支持,也是一个很老的特性了。DeferredResult可以允许容器线程快速释放以便可以接受更多的请求提升吞吐量,让真正的业务逻辑在其他的工作线程中去完成。
最近再看apollo配置中心的实现原理,apollo的发布配置推送变更消息就是用DeferredResult实现的,apollo客户端会像服务端发送长轮训localhost:8080/watch/mynamespace,请求会挂起,60秒后,DeferredResult超时,客户端正常收到了304状态码,表明在这个期间配置没有变更过。
然后我们在模拟配置变更的情况,再次发起请求localhost:8080/watch/mynamespace,等待个10秒钟(不要超过60秒),然后调用localhost:8080/publish/mynamespace,发布配置变更。这时postman会立刻收到response响应结果:
mynamespace changed:1538880050147
表明在轮训期间有配置变更过。
这里我们用了一个MultiMap来存放所有轮训的请求,Key对应的是namespace,value对应的是所有watch这个namespace变更的异步请求DeferredResult,需要注意的是:在DeferredResult完成的时候记得移除MultiMap中相应的key,避免内存溢出请求。
采用这种长轮询的好处是,相比一直循环请求服务器,实例一多的话会对服务器产生很大的压力,http长轮询的方式会在服务器变更的时候主动推送给客户端,其他时间客户端是挂起请求的,这样同时满足了性能和实时性。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持易盾网络。如有错误或未考虑完全的地方,望不吝赐教。

