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