關(guān)于springboot響應(yīng)式編程整合webFlux的問題
在servlet3.0標(biāo)準(zhǔn)之前,是每一個請求對應(yīng)一個線程。如果此時一個線程出現(xiàn)了高延遲,就會產(chǎn)生阻塞問題,從而導(dǎo)致整個服務(wù)出現(xiàn)嚴(yán)重的性能情況,因為一旦要調(diào)用第三方接口,就有可能出現(xiàn)這樣的操作了。早期的處理方式只能是手工控制線程。
在servlet3.0標(biāo)準(zhǔn)之后,為了解決此類問題,所以提供了異步響應(yīng)的支持。在異步響應(yīng)處理結(jié)構(gòu)中,可以將耗時操作的部分交由一個專屬的異步線程進(jìn)行響應(yīng)處理,同時請求的線程資源將被釋放,并將該線程返回到線程池中,以供其他用戶使用,這樣的操作機(jī)制將極大的提升程序的并發(fā)性能。
對于以上給出的響應(yīng)式編程支持,僅僅是一些原生的支持模式,而現(xiàn)在既然基于springboot程序開發(fā),那么就需要考慮一些更簡單的整合。
而在spring中實現(xiàn)響應(yīng)式編程,那么則需要使用到spring webFlux,該組件是一個重新構(gòu)建的且基于Reactive Streams標(biāo)準(zhǔn)實現(xiàn)的異步非阻塞Web開發(fā)框架,以Reactor開發(fā)框架為基礎(chǔ),可以更加容易實現(xiàn)高并發(fā)訪問下的請求處理模型。在springboot2.x版本中提供了webFlux依賴模塊,該模塊有兩種模型實現(xiàn):一種是基于功能性端點的方式,另一種是基于SpringMVC注解方式。
Maven引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
整合處理器:
package com.example.oldguy.myWebFlux.handler; import com.example.oldguy.myVo.Message; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; @Component @Slf4j public class MessageHandler { public Mono<Message> echoHandler(Message message){ log.info("【{}】業(yè)務(wù)層接收處理數(shù)據(jù):{}",Thread.currentThread().getName()); message.setTitle("【】"+Thread.currentThread().getName()+"】"+message.getTitle()); message.setContent("【】"+Thread.currentThread().getName()+"】"+message.getContent()); return Mono.create(item->item.success(message)); //實現(xiàn)數(shù)據(jù)響應(yīng) } }
整合控制器:
package com.example.oldguy.myController; import com.example.oldguy.myVo.Message; import com.example.oldguy.myWebFlux.handler.MessageHandler; import com.example.oldguy.mytask.MyThreadTask; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.async.DeferredResult; import javax.servlet.http.HttpServletRequest; import java.beans.PropertyEditorSupport; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.concurrent.TimeUnit; /** * 異步線程的處理機(jī)制 */ @RestController @RequestMapping("/message/*") @Slf4j @Api(tags = "異步處理") public class AsyncController { @Autowired private ThreadPoolTaskExecutor threadPoolTaskExecutor; private MyThreadTask task; private MessageHandler messageHandler; /** * 日期轉(zhuǎn)換 * @param * @return */ private static final DateTimeFormatter LOCAL_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @InitBinder public void initBinder(WebDataBinder binder){ binder.registerCustomEditor(Date.class,new PropertyEditorSupport(){ @Override public void setAsText(String text) throws IllegalArgumentException { LocalDate localDate = LocalDate.parse(text,LOCAL_DATE_FORMAT); Instant instant = localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant(); super.setValue(Date.from(instant)); } }); } @GetMapping("runnable") @ApiOperation("異常處理Runnable") public Object message(String message) { log.info("外部線程:{}", Thread.currentThread().getName()); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); DeferredResult<String> result = new DeferredResult<>(6000L); //設(shè)置異步響應(yīng) this.threadPoolTaskExecutor.execute(new Runnable() { //線程核心任務(wù) @SneakyThrows public void run() { log.info("內(nèi)部線程:{}",Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(7); result.setResult("[echo]"+message); //執(zhí)行最終的響應(yīng) result.onCompletion(new Runnable() { //完成處理線程 log.info("完成線程:{}",Thread.currentThread().getName()); //日志輸出 result.onTimeout(new Runnable() { log.info("超時線程:{}",Thread.currentThread().getName()); result.setResult("【請求超時】"+request.getRequestURI()); //超時路徑 return result; @GetMapping("task") @ApiOperation("task異步任務(wù)開啟") public Object messageTask(String message){ log.info("外部線程{}",Thread.currentThread().getName()); this.task.startTaskHander(); return "【echo】"+message; @GetMapping("webflux") @ApiOperation("整合webflux") public Object echo(Message message){ log.info("接收用戶信息,用戶方發(fā)送的參數(shù)為message={}",message); return this.messageHandler.echoHandler(message); }
頁面響應(yīng):
控制臺響應(yīng):
2021-11-30 15:04:06.946 INFO 22884 --- [nio-1999-exec-1] c.e.oldguy.myController.AsyncController : 接收用戶信息,用戶方發(fā)送的參數(shù)為message=Message(title=pansd, pubdate=Tue Nov 30 00:00:00 CST 2021, content=come on baby)
2021-11-30 15:04:06.947 INFO 22884 --- [nio-1999-exec-1] c.e.o.myWebFlux.handler.MessageHandler : 【http-nio-1999-exec-1】業(yè)務(wù)層接收處理數(shù)據(jù):Message(title=pansd, pubdate=Tue Nov 30 00:00:00 CST 2021, content=come on baby)
webFlux響應(yīng)map和List
//webFlux響應(yīng)集合 public Flux<Message> list(Message message){ List<Message> messageList = new ArrayList<>(); for(int i=0;i<10;i++){ Message m = new Message(); m.setTitle(i+"--"+message.getTitle()); m.setContent(i+"--"+message.getContent()); m.setPubdate(message.getPubdate()); messageList.add(m); } return Flux.fromIterable(messageList); } public Flux<Map.Entry<String,Message>> map(Message message){ Map<String,Message> map = new HashMap<>(); for(int i=0;i<10;i++){ Message m = new Message(); m.setTitle(i+"--"+message.getTitle()); m.setContent(i+"--"+message.getContent()); m.setPubdate(message.getPubdate()); map.put("pansd-"+i,m); } // Set<Map.Entry<String, Message>> entries = map.entrySet(); return Flux.fromIterable(map.entrySet()); }
@GetMapping("webfluxList") @ApiOperation("整合webfluxList") public Object echoList(Message message){ log.info("接收用戶信息,用戶方發(fā)送的參數(shù)為message={}",message); return this.messageHandler.list(message); } @GetMapping("webfluxMap") @ApiOperation("整合webfluxMap") public Object echoMap(Message message){ log.info("接收用戶信息,用戶方發(fā)送的參數(shù)為message={}",message); return this.messageHandler.map(message); }
到此這篇關(guān)于springboot響應(yīng)式編程整合webFlux的文章就介紹到這了,更多相關(guān)springboot響應(yīng)式編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot 使用@WebMvcTest測試MVC Web Controller
- SpringBoot中通過實現(xiàn)WebMvcConfigurer參數(shù)校驗的方法示例
- springboot webflux 過濾器(使用RouterFunction實現(xiàn))
- SpringBoot之webflux全面解析
- SpringBoot?Webflux創(chuàng)建TCP/UDP?server并使用handler解析數(shù)據(jù)
- Springboot WebFlux集成Spring Security實現(xiàn)JWT認(rèn)證的示例
- SpringBoot2使用WebFlux函數(shù)式編程的方法
- SpringBoot深入分析webmvc和webflux的區(qū)別
相關(guān)文章
Java ArrayList中存放引用數(shù)據(jù)類型的方式
這篇文章主要介紹了Java ArrayList中存放引用數(shù)據(jù)類型的方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10Java中使用LocalDate根據(jù)日期來計算年齡的實現(xiàn)方法
這篇文章主要介紹了Java中使用LocalDate根據(jù)日期來計算年齡的實現(xiàn)方法,需要的朋友可以參考下2018-01-01JavaWeb中struts2實現(xiàn)文件上傳下載功能實例解析
這篇文章主要介紹了JavaWeb中struts2文件上傳下載功能的實現(xiàn),在Web應(yīng)用系統(tǒng)開發(fā)中,文件上傳和下載功能是非常常用的功能,需要的朋友可以參考下2016-05-05如何在mybatis中向BLOB字段批量插入數(shù)據(jù)
這篇文章主要介紹了如何在mybatis中向BLOB字段批量插入數(shù)據(jù)的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-10-10RecyclerChart動態(tài)屬性圖標(biāo)聯(lián)動數(shù)據(jù)動態(tài)加載詳解
這篇文章主要為大家介紹了RecyclerChart動態(tài)屬性圖標(biāo)聯(lián)動數(shù)據(jù)動態(tài)加載詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03