FeignClient Configuration属性使用

  • A+
所属分类:SpringCloud

FeignClient Configuration属性

可以针对不同的服务客户端使用不同的配置

具体配置项如下,如何配置可以参考FeignClientsConfiguration

  1. # RequestInterceptor:请求拦截器

通过Feign Client,实际上Request已经是经过了转发的,不再是原始的Request,调用的时候仅仅传递了参数,而Header等却没有继续传递,因此需要进行特殊处理:

修改service-hi

FeignClient Configuration属性使用

使用postman访问http://127.0.0.1:8101/hiFeign/qzkj

并添加header信息

FeignClient Configuration属性使用

返回的信息中header信息丢失

此时可以通过@FeignClient的Configuration属性自定义配置来处理header丢失的问题

新建配置类,使用@Configuration标注,内容如下:

FeignClient Configuration属性使用

修改FeignService

FeignClient Configuration属性使用

修改application.yml

FeignClient Configuration属性使用

hystrix.command.default.execution.isolation.strategy:用来设置执行的隔离策略,有如下二个选项:

THREAD:通过线程池隔离的策略,在独立线程上执行,并且他的并发限制受线程池中线程数量的限制(默认)

THREAD测试多线程下Feign客户端是否正常调用

 

 

SEMAPHONE:通过信号量隔离的策略,在调用线程上执行,并且他的并发限制受信号量计数的限制。

默认策略会导致上面的HeaderConfig.java attributes.getRequest()空指针异常,下文中会提到解决方法

 

 

注意属性需要大写,小写启动报错

 

重启Feign服务,再通过postman访问

FeignClient Configuration属性使用

 

 

使用默认策略的处理方法:

重写HystrixConcurrencyStrategy

1
 
1
2
java
   public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy { private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategy.class); private HystrixConcurrencyStrategy delegate; public FeignHystrixConcurrencyStrategy() { try { this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy(); if (this.delegate instanceof FeignHystrixConcurrencyStrategy) { // Welcome to singleton hell... return; } HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook(); HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier(); HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher(); HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy(); this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy); HystrixPlugins.reset(); HystrixPlugins.getInstance().registerConcurrencyStrategy(this); HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook); HystrixPlugins.getInstance().registerEventNotifier(eventNotifier); HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher); HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy); } catch (Exception e) { log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e); } } private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier, HystrixMetricsPublisher metricsPublisher, HystrixPropertiesStrategy propertiesStrategy) { if (log.isDebugEnabled()) { log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy [" + this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher [" + metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]"); log.debug("Registering Sleuth Hystrix Concurrency Strategy."); } } @Override public <t> Callable</t><t> wrapCallable(Callable</t><t> callable) { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); return new WrappedCallable<>(callable, requestAttributes); } @Override public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixProperty<integer> corePoolSize, HystrixProperty</integer><integer> maximumPoolSize, HystrixProperty</integer><integer> keepAliveTime, TimeUnit unit, BlockingQueue<runnable> workQueue) { return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } @Override public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) { return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties); } @Override public BlockingQueue</runnable><runnable> getBlockingQueue(int maxQueueSize) { return this.delegate.getBlockingQueue(maxQueueSize); } @Override public <t> HystrixRequestVariable</t><t> getRequestVariable(HystrixRequestVariableLifecycle</t><t> rv) { return this.delegate.getRequestVariable(rv); } static class WrappedCallable</t><t> implements Callable</t><t> { private final Callable</t><t> target; private final RequestAttributes requestAttributes; public WrappedCallable(Callable</t><t> target, RequestAttributes requestAttributes) { this.target = target; this.requestAttributes = requestAttributes; } @Override public T call() throws Exception { try { RequestContextHolder.setRequestAttributes(requestAttributes); return target.call(); } finally { RequestContextHolder.resetRequestAttributes(); } } } }
1
 

配置类中添加如下代码:

@Bean
public FeignHystrixConcurrencyStrategy feignHystrixConcurrencyStrategy() {
return new FeignHystrixConcurrencyStrategy();
}

修改application.yml

FeignClient Configuration属性使用

即可正常访问

  1. # FeignLoggerFactory:日志工厂

新建自定义日志类和自定义日志工厂类

FeignClient Configuration属性使用

FeignClient Configuration属性使用

新建配置类,修改日志级别为FULL

FeignClient Configuration属性使用

修改FeignService

FeignClient Configuration属性使用

重启,使用postman访问,此时后台可以看到请求的详细信息

FeignClient Configuration属性使用

通过日志发现token丢失,可以通过Configuration指定多个配置文件,结合7.1中的RequestInterceptor解决问题

修改FeignService

FeignClient Configuration属性使用

重启后再次访问

FeignClient Configuration属性使用

  1. # Decoder解码器

将一个http响应转换成一个对象,Spring Cloud Feign 默认使用ResponseEntityDecoder

@Bean
Decoder feignDecode(){
return new FeignDecode();
//return new Decoder.Default();
}
public static class FeignDecode extends StringDecoder {
public FeignDecode() {
}

public Object decode(Response response, Type type) throws IOException {
if (response.status() == 404) {
return Util.emptyValueOf(type);
} else if (response.body() == null) {
return null;
} else {
return byte[].class.equals(type) ? Util.toByteArray(response.body().asInputStream()) : super.decode(response, type);
}
}
}

 

  1. # Encoder编码器

将一个对象转换成http请求体中,Spring Cloud Feign 默认使用SpringEncoder

@Bean
Encoder feignEncoder(){
return new Encoder() {
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) {
if (bodyType == String.class) {
template.body(object.toString());
} else if (bodyType == byte[].class) {
template.body((byte[])((byte[])object), (Charset)null);
} else if (object != null) {
throw new EncodeException(String.format("%s is not a type supported by this encoder.", object.getClass()));
}
}
};
//return new Encoder.Default();
}

 

  1. # Contract:处理Feign接口注解

Spring Cloud Feign使用SpringMvcContract 实现,处理Spring mvc 注解,也就是我们为什么可以用Spring mvc 注解的原因。

 

  1. # Retryer:重试机制

@Bean
Retryer feignRetryer(){
Retryer NEVER_RETRY = new Retryer() {
public void continueOrPropagate(RetryableException e) {
throw e;
}

public Retryer clone() {
return this;
}
};
return NEVER_RETRY;
//return Retryer.NEVER_RETRY;
}

 

  1. # Feign.BuilderFeign接口构建类

覆盖默认Feign.Builder,比如:HystrixFeign.Builder

@Bean
Feign.Builder feignBuilder(){
return Feign.builder(); //默认
}

 

  1. # Logger.Level:日志级别

@Bean
/**
*日志级别
* NONE, 默认
* BASIC,
* HEADERS,
*FULL;
*/
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}

 

  1. # ErrorDecoder:错误解码器

@Bean
/**
* 错误解码器
*/
ErrorDecoder feignErrorDecoder(){
return new ErrorDecoder.Default();
}

 

  1. # FeignContext

管理了所有的java config 配置

@Bean
FeignContext feignContext(){
return new FeignContext();
}

weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: