遇到的问题

SpringCloud 升级到 2020.4 后,网关Gateway启动不了,没有报错,一直卡住。
只要 @Autowired 注入 OpenFeignClient ,就启动不起来。

升级后环境

SpringCloud版本: 2020.0.4
SpringCloudAlibaba版本: 2021.1
SpringBoot版本: 2.5.7

解决办法

有以下几个需要注意的地方:

  1. 注入OpenFeignClient 必须使用 @Lazy
  2. FeignClient 必须要异步调用,使用Future方式,不能同步调用,不然会报不能在xxx线程执行的错。读者可以自行尝试下哈。
  3. 使用 @EnableFeignClients ,开启 OpenFeign 功能
  4. 使用 @EnableAsync 开启异步执行功能,不然加了 @Async 注解也没用哦。

主要的代码示例

OpenFeignClient 定义

// 我这里降级啥的都没写哦
@FeignClient(name = "system", decode404 = true)
public interface SystemFeignClient {

    @GetMapping("/test")
    String test(@RequestParam("id") String id);
    
}

OpenFeignClien注入示例

// 这个类的作用,是将Client包装一层,在这里做异步处理
@Slf4j
@Component
public class ClientHolder {

    @Lazy // 重点:这里必须使用@Lazy
    @Autowired
    private SystemFeignClient systemFeignClient;

    @Async // 重点:这里必须在异步线程中执行,执行结果返回Future
    public Future<String> systemClientTest() {
        log.info("开始使用SystemClient...");
        String s = systemFeignClient.test("1001");
        return new AsyncResult<>(s);
    }
}

在Filter中使用

在其他Bean中使用是一样的哈。

@Slf4j
@Component
public class TestFilter implements GlobalFilter, Ordered {
    @Autowired
    private ClientHolder clientHolder;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        callClient();
        return chain.filter(exchange);
    }
    private void callClient() {
    	// 使用Client
        Future<String> stringFuture = clientHolder.systemClientTest();
        try {
            log.info("stringFuture.rs :{}", stringFuture.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

异步线程池配置

@Configuration
@EnableAsync(proxyTargetClass = true)
public class AsycTaskConfig {

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 我这里是固定写死的哦,实际不能这样写的哦
        // 可以使用 Runtime.getRuntime().availableProcessors() 获取系统核心数进行配置
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(8);
        executor.setQueueCapacity(1000);
        executor.setThreadNamePrefix("my-core-"); 
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

完整代码

完整代码链接 码云地址

写在最后

笔者刚开始写博客,若是帮助到您,帮忙点赞推荐下哦 ~

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐