The solution to the problem of missing request headers when calling feign remotely (including the use of thread pool to make asynchronous feign calls)

Add configuration information

#配置自定义的线程池
gulimall.thread.core-size=20
gulimall.thread.max-size=200
gulimall.thread.keep-alive-time=10

Add configuration class

//跟配置文件绑定
@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
    
    

    private Integer coreSize;
    private Integer maxSize;
    private Integer keepAliveTime;
}

Add thread pool configuration class

//开启属性配置(因为ThreadPoolConfigProperties写了@Component,所以就不用写了)
//@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig {
    
    
    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
    
    
        return new ThreadPoolExecutor(pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(), TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }
}

In the process of feign calling the remote service, the filter will be called layer by layer. We need to re-assign the information in the request header passed by the front end to the new request in the requestInterceptor interceptor, so here we add a configuration class: this The method can solve the situation where only a feign request is called synchronously.

@Configuration
public class GuliFeignConfig {
    
    
    @Bean
    public RequestInterceptor requestInterceptor() {
    
    

        return new RequestInterceptor() {
    
    

            @Override
            public void apply(RequestTemplate template) {
    
    

                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                if (attributes != null) {
    
    
                    HttpServletRequest request = attributes.getRequest();
                    if (request != null) {
    
    
                        //同步请求头数据 主要同步Cookie
                        String cookie = request.getHeader("Cookie");
                        //给新请求同步的老请求Cookie
                        template.header("Cookie", cookie);
                    }
                }
            }
        };
    }
}
  • In our development process, we may encounter the situation of using the thread pool to call other services asynchronously. Because when we start the thread asynchronous call, we reacquire a thread in the thread pool, so there will be no request header information. If other service modules need to authenticate the token and other information in the request header, what should we do?
  • Feign + asynchronous tasks need to share RequestAttributes. Each task must setRequestAttributes(), take the parameters in the request header passed by the front end and re-assign them to the new thread in the thread pool.
@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    
    
    @Autowired
    MemberFeignService memberFeignService;

    @Autowired
    CartFeignService cartFeignService;
    @Autowired
    WareFeignServicewareFeignService;
    @Autowired
    ThreadPoolExecutor executor;
    //共享前端页面传过来的vo
    ThreadLocal<OrderSubmitVo> confirmVoThreadLocal = new ThreadLocal<>();

/**
     * 去结算
     * 给订单确认ye返回数据
     */
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
    
    

        //要返回的大对象
        OrderConfirmVo confirmVo = new OrderConfirmVo();

        //在TreadLocal中获取用户
        MemberResVo memberResVo = LoginUserInterceptor.loginUser.get();

        //Feign + 异步任务 需要共享RequestAttributes 每个任务都要setRequestAttributes(),将前端传递过来的请求头里面的参数取出来再重新赋值给线程池里面的新线程。
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
    
    
            //每一个线程都要共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //1 远程查询大对象的第一个属性 收货地址列表
            List<MemberAddressVo> address = memberFeignService.getAddress(memberResVo.getId());
            confirmVo.setAddress(address);
            //Feign在远程调用之前要构造请求,调用很多的拦截器
        }, executor);

        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
    
    
            //每一个线程都要共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //2 远程查询大对象的第二个属性 所有购物项
            List<OrderItemVo> items = cartFeignService.currentUserItems();
            confirmVo.setItems(items);
        }, executor).thenRunAsync(() -> {
    
    
            //执行下一个任务线程
            R r = wareFeignService.getSkuHasStock(ids);
        }, executor);
        CompletableFuture.allOf(getAddressFuture, cartFuture).get();
        return confirmVo;
    }
}

Guess you like

Origin blog.csdn.net/u014496893/article/details/114144850