原创

SpringCloud-Feign 开发遇到的问题

什么是feign

feign是一种声明式的web server客户端,微服务之间调用的工具,默认集成ribbon和eureka,可以在使用feign时提供负载均衡的http客户端。


我这边是重新新建了一个工程,把feign组件写在里面,这样有需要使用的项目只需要引入feign工程就可以了。


Maven引入

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version> ? </version>
</dependency>


Config配置

/**
* @autor: 木杉
* create on 2020/8/11
* email: 819236727@qq.com
* describe:
*/
@Configuration
@EnableFeignClients(basePackageClasses = com.fccn.feign.order.OrderFeign.class)
public class FeignClientsConfiguration implements RequestInterceptor{
@Value("${fccn.config.fcAppToken}")
private String token;

@Override
public void apply(RequestTemplate template) {
template.header("fcAppToken",token);
}

@Bean
public HystrixFallBack orderHystrixFallBack(){
return new HystrixFallBack();
}
}


Feign组件

/**
* @autor: 木杉
* create on 2020/8/11
* email: 819236727@qq.com
* describe:
*/
@FeignClient(value = "ORDER-SERVER",fallback = HystrixFallBack.class)
public interface OrderFeign {
@PostMapping(value = "/feign/testAdd")
public String testAdd(@RequestBody Map<String,String> id);
}


HystrixFallBack

发生熔断时候,触发的操作,如果不使能熔断器可以不用弄这个

/**
* @autor: 木杉
* create on 2020/8/11
* email: 819236727@qq.com
* describe:
*/
@Slf4j
public class HystrixFallBack implements OrderFeign {
@Override
public String testAdd(Map<String, String> id) {
return null;
}
}


注入SpringBean

这个时候要注意了,可能会存在项目引入feign工程会扫描不到的情况,这个时候可以手动添加


在路径resources.META-INF 下新建名为spring.factories的文件
内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
xxx.xxx.xxx.xxx.xxx.FeignClientsConfiguration
将xxx改为你的Config配置的路径,这样spring就可以扫描到了


这个时候也算是大功告成了,但是feign组件这个时候是默认不开启熔断器的。

Hystrix开启

application.yml加入
feign:
hystrix:
enabled: true

spring:
feign:
hystrix:
enabled: true

hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 8000

ribbon:
connectTimeout: 8000
readTimeout: 8000

开启熔断器后是采用线程隔离的策略,也就是不能通过((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();方式获取当前的头部信息

需要重写隔离策略:
package com.fccn.feign.wechat.config;

import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
* @Author: 木杉
* @e-mail: 819236727@qq.com
* @Date: 2021/1/25
* @Destrice:
*/
@Component
public class RequestAttributeHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy{
private final Logger log = LoggerFactory.getLogger(getClass());

private HystrixConcurrencyStrategy delegate;

public RequestAttributeHystrixConcurrencyStrategy() {
try {
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
if (this.delegate instanceof RequestAttributeHystrixConcurrencyStrategy) {
// 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) {

}
}

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> wrapCallable(Callable<T> callable) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return new WrappedCallable<>(callable, requestAttributes);
}

@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixProperty<Integer> corePoolSize,
HystrixProperty<Integer> maximumPoolSize,
HystrixProperty<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> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}

@Override
public <T> HystrixRequestVariable<T> getRequestVariable(
HystrixRequestVariableLifecycle<T> rv) {
return this.delegate.getRequestVariable(rv);
}

static class WrappedCallable<T> implements Callable<T> {

private final Callable<T> target;
private final RequestAttributes requestAttributes;

public WrappedCallable(Callable<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();
}
}
}
}

重写之后就可以通过((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();获取到HttpServletRequest了。

正文到此结束
该篇文章的评论功能已被站长关闭