需求说明:在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); } } }