需求说明:在gateway服务里面需要调用其他服务的接口
问题分析:1.在GlobalFilter过滤类中获取feign服务类时,用@Autowired注解获取会报错,这和servlet, filter的加载顺序有关,所以使用AutowiredBean类,原理是从spring上下文中获取feign的自定义Bean,然后在正常调用接口。获取feign服务类AutowiredBean代码如下:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
public class AutowiredBean{
private static ApplicationContext applicationContext;
public static void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (AutowiredBean.applicationContext == null) {
AutowiredBean.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
2.在过滤类中正常调用feign服务接口时,会抛出一个java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2,意思是线程堵塞,使用CompletableFuture.supplyAsync异步调用解决。
解决代码,GlobalFilter过滤类代码如下::
@Component
public class InnerFilter implements GlobalFilter, Ordered {
@SneakyThrows
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取的关键看这里,在用的时候在获取服务bean
SysLogClient sysLogClient = AutowiredBean.getBean(SysLogClient.class);
//异步调用feign服务接口
CompletableFuture<HttpResult> f = CompletableFuture.supplyAsync(()->{
// 此时就去调用服务的接口方法
return sysLogClient.getSysLogListWithPage(0, 10, "cs");
});
HttpResult result = f.get();
// TODO 这里未来还可以限制一些格式
return chain.filter(exchange.mutate().request(exchange.getRequest()).build());
}
/**
* 优先级默认设置为最高
*
* @return
*/
@Override
public int getOrder() {
return -800;
}
}
3.FeignConfig类解决异步调用 feign 的错误,不加这个类会抛一个异常java.util.concurrent.ExecutionException: feign.codec.DecodeException: No qualifying bean of type 'org.springframework.boot.autoconfigure.http.HttpMessageConverters' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
解决代码,Feign配置类,解决异步调用 feign 的错误:
/**
* Feign 配置
* @author: lsz
* @time: 2021/10/15
*/
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLevel() {
//这里记录所有
return Logger.Level.FULL;
}
@Bean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new SpringDecoder(feignHttpMessageConverter()));
}
public ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(new PhpMappingJackson2HttpMessageConverter());
return new ObjectFactory<HttpMessageConverters>() {
@Override
public HttpMessageConverters getObject() throws BeansException {
return httpMessageConverters;
}
};
}
public class PhpMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
PhpMappingJackson2HttpMessageConverter(){
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.valueOf(MediaType.TEXT_HTML_VALUE + ";charset=UTF-8"));
setSupportedMediaTypes(mediaTypes);
}
}
}