需求说明:在gateway服务里面需要调用其他服务的接口
问题分析:1.在GlobalFilter过滤类中获取feign服务类时,用@Autowired注解获取会报错,这和servlet, filter的加载顺序有关,所以使用AutowiredBean类,原理是从spring上下文中获取feign的自定义Bean,然后在正常调用接口
2.在过滤类中正常调用feign服务接口时,会抛出一个java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2,意思是线程堵塞,使用CompletableFuture.supplyAsync异步调用解决
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)}
1.GlobalFilter过滤类
1 @Component
2 public class InnerFilter implements GlobalFilter, Ordered {
3
4 @SneakyThrows
5 @Override
6 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
7 SysLog sysLog = new SysLog();
8 sysLog.setLoginName("lsz");
9
10 //获取的关键看这里,在用的时候在获取bean
11 SysLogClient sysLogClient = AutowiredBean.getBean(SysLogClient.class);
12 //异步调用feign服务接口
13 CompletableFuture<HttpResult> f = CompletableFuture.supplyAsync(()->{
14 return sysLogClient.getSysLogListWithPage(0, 10, "ad");
15 });
16
17 HttpResult result = f.get();
18 // TODO 这里未来还可以限制一些格式
19 return chain.filter(exchange.mutate().request(exchange.getRequest()).build());
20 }
21
22 /**
23 * 优先级默认设置为最高
24 *
25 * @return
26 */
27 @Override
28 public int getOrder() {
29 return -800;
30 }
31 }
2.获取feign服务类AutowiredBean
1 2
3 import org.springframework.beans.BeansException;
4 import org.springframework.context.ApplicationContext;
5
6 public class AutowiredBean{
7
8 private static ApplicationContext applicationContext;
9
10 public static void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
11 if (AutowiredBean.applicationContext == null) {
12 AutowiredBean.applicationContext = applicationContext;
13 }
14 }
15
16 public static ApplicationContext getApplicationContext() {
17 return applicationContext;
18 }
19
20 public static Object getBean(String name) {
21 return getApplicationContext().getBean(name);
22 }
23
24 public static <T> T getBean(Class<T> clazz) {
25 return getApplicationContext().getBean(clazz);
26 }
27
28 public static <T> T getBean(String name, Class<T> clazz) {
29 return getApplicationContext().getBean(name, clazz);
30 }
31
32 }
3. Feign配置类,解决异步调用 feign 的错误
package com.hnlt.cloud.gateway.config;
import feign.Logger;
import feign.codec.Decoder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.util.ArrayList;
import java.util.List;
/**
* 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);
}
}
}