解決在微服務(wù)環(huán)境下遠(yuǎn)程調(diào)用feign和異步線程存在請求數(shù)據(jù)丟失問題
一、無異步線程得情況下feign遠(yuǎn)程調(diào)用:
1、登錄攔截器:
@Component public class LoginUserInterceptor implements HandlerInterceptor { public static ThreadLocal<MemberResVo> loginUser = new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //獲取登錄用戶的鍵 MemberResVo attribute = (MemberResVo) request.getSession().getAttribute(AuthServerConstant.LONG_USER); if (attribute!=null){ loginUser.set(attribute); return true; }else { request.getSession().setAttribute("msg","請先進(jìn)行登錄!"); response.sendRedirect("http://auth.gulimall.com/login.html"); return false; } } }
2.問題示例圖:
3.解決方法:
import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; @Configuration public class GuliFeignConfig { //fegin過濾器 @Bean("requestInterceptor") public RequestInterceptor requestInterceptor() { return new RequestInterceptor() { public void apply(RequestTemplate template) { //上下文環(huán)境保持器,拿到剛進(jìn)來這個(gè)請求包含的數(shù)據(jù),而不會因?yàn)檫h(yuǎn)程數(shù)據(jù)請求頭被清除 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest();//老的請求 if (request != null) { //同步老的請求頭中的數(shù)據(jù),這里是獲取cookie String cookie = request.getHeader("Cookie"); template.header("Cookie", cookie); } } }; } }
二、異步情況下丟失上下文問題:
① 在同一線程下進(jìn)行遠(yuǎn)程調(diào)用,即一連串調(diào)用的情況下OrederService通過遠(yuǎn)程調(diào)用先查找adress信息,再查找cart信息,則僅需配置GuliFeignConfig就夠了
② 由于采用的異步任務(wù),所以101、102線程在自己的線程中調(diào)用登錄攔截器interceptor,而其實(shí)只有在72號線程中登陸攔截器才進(jìn)行放行(有請求頭數(shù)據(jù)),這就導(dǎo)致101、102的request為null
解決方式(高亮部分):從總線中獲取request數(shù)據(jù)放入子線程中
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes()
@Service("orderService") public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService { @Autowired MemberFeignService memberFeignService; @Autowired CartFeginService cartFeginService; @Autowired ThreadPoolExecutor executor; @Autowired WmsFeignService wmsFeignService; /** * 訂單確認(rèn)頁返回的數(shù)據(jù) * @return */ @Override public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException { OrderConfirmVo confirmVo = new OrderConfirmVo(); MemberResVo memberResVo = LoginUserInterceptor.loginUser.get(); //從主線程中獲得所有request數(shù)據(jù) RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> { //1、遠(yuǎn)程查詢所有地址列表 RequestContextHolder.setRequestAttributes(requestAttributes); List<MemberAddressVo> address = memberFeignService.getAddress(memberResVo.getId()); confirmVo.setAddress(address); }, executor); //2、遠(yuǎn)程查詢購物車所選的購物項(xiàng),獲得所有購物項(xiàng)數(shù)據(jù) CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> { //放入子線程中request數(shù)據(jù) RequestContextHolder.setRequestAttributes(requestAttributes); List<OrderItemVo> items = cartFeginService.getCurrentUserCartItems(); confirmVo.setItem(items); }, executor).thenRunAsync(()->{ RequestContextHolder.setRequestAttributes(requestAttributes); List<OrderItemVo> items = confirmVo.getItem(); List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList()); //遠(yuǎn)程調(diào)用查詢是否有庫存 R hasStock = wmsFeignService.getSkusHasStock(collect); //形成一個(gè)List集合,獲取所有物品是否有貨的情況 List<SkuStockVo> data = hasStock.getData(new TypeReference<List<SkuStockVo>>() { }); if (data!=null){ //收集起來,Map<Long,Boolean> stocks; Map<Long, Boolean> map = data.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock)); confirmVo.setStocks(map); } },executor); //feign遠(yuǎn)程調(diào)用在調(diào)用之前會調(diào)用很多攔截器,因此遠(yuǎn)程調(diào)用會丟失很多請求頭 //3、查詢用戶積分 Integer integration = memberResVo.getIntegration(); confirmVo.setIntegration(integration); //其他數(shù)據(jù)自動(dòng)計(jì)算 CompletableFuture.allOf(getAddressFuture,cartFuture).get(); return confirmVo; } }
到此這篇關(guān)于解決在微服務(wù)環(huán)境下遠(yuǎn)程調(diào)用feign和異步線程存在請求數(shù)據(jù)丟失問題的文章就介紹到這了,更多相關(guān)feign遠(yuǎn)程調(diào)用請求丟失內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實(shí)現(xiàn)人臉識別等多種登錄方式
本文主要介紹了SpringBoot實(shí)現(xiàn)人臉識別等多種登錄方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05Spring配置動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)讀寫分離的方法
這篇文章主要介紹了利用Spring配置動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)讀寫分離的方法,文中通過示例代碼介紹的很詳細(xì),相信對大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值,藕需要的朋友可以一起學(xué)習(xí)學(xué)習(xí)。2017-01-01Java HashSet(散列集),HashMap(散列映射)的簡單介紹
這篇文章主要介紹了Java HashSet(散列集),HashMap(散列映射)的簡單介紹,幫助大家更好的理解和學(xué)習(xí)Java集合框架的相關(guān)知識,感興趣的朋友可以了解下2021-01-01Java解析Excel文件并把數(shù)據(jù)存入數(shù)據(jù)庫
本篇文章主要介紹了Java解析Excel文件并把數(shù)據(jù)存入數(shù)據(jù)庫 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05Java selenium上傳文件的實(shí)現(xiàn)
本文主要介紹了Java selenium上傳文件的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04Java編程實(shí)現(xiàn)統(tǒng)計(jì)一個(gè)字符串中各個(gè)字符出現(xiàn)次數(shù)的方法
這篇文章主要介紹了Java編程實(shí)現(xiàn)統(tǒng)計(jì)一個(gè)字符串中各個(gè)字符出現(xiàn)次數(shù)的方法,涉及java針對字符串的遍歷、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12Java使用quartz實(shí)現(xiàn)定時(shí)任務(wù)示例詳解
這篇文章主要為大家介紹了Java使用quartz實(shí)現(xiàn)定時(shí)任務(wù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08如何在springboot中引入?yún)?shù)校驗(yàn)
一般我們判斷前端傳過來的參數(shù),需要對某些值進(jìn)行判斷,是否滿足條件,而springboot相關(guān)的參數(shù)校驗(yàn)注解,可以解決我們這個(gè)問題,本文給大家介紹如何在springboot中引入?yún)?shù)校驗(yàn),感興趣的朋友一起看看吧2023-12-12