feign+hystrix根據serviceId配置hystrix.command

在使用feign+hystrix時,hystrix.command相關的屬性的優先級是

hystrix.command.FeignClient#Method() -> hystrix.command.default

如果我們希望優先級是

hystrix.command.FeignClient#Method() -> hystrix.command.FeignClient#name -> hystrix.command.default

目前通過配置沒有找到相關的方法,要想實現,就只有改代碼了;但是改代碼要改哪些呢?
1、覆蓋原來的HystrixFeign$Builder
2、重寫SetterFactory方法

代碼如下

import com.netflix.hystrix.HystrixCommand;
import feign.Feign;
import feign.hystrix.HystrixFeign;
import feign.hystrix.SetterFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.ConfigurableEnvironment;

@Configuration
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
public class FeignHystrixConfiguration {

    @Autowired
    private ConfigurableEnvironment environment;


    @Bean
    @Scope("prototype")
    @ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = false)
    public Feign.Builder feignHystrixBuilder() {
        return HystrixFeign.builder().setterFactory(getSetterFactory());
    }

    private SetterFactory getSetterFactory(){
        return new FmSetterFactory(environment);
    }
}
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import feign.Feign;
import feign.Target;
import feign.hystrix.SetterFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import java.lang.reflect.Method;
import java.util.Optional;

public class FmSetterFactory implements SetterFactory {

    private static final String HYSTRIX_COMMAND_PREFIX = "hystrix.command";

    private ConfigurableEnvironment environment;

    public FmSetterFactory(ConfigurableEnvironment environment) {
        this.environment = environment;
    }

    @Override
    public HystrixCommand.Setter create(Target<?> target, Method method) {
        String groupKey = target.name();
        String commandKey = Feign.configKey(target.type(), method);


        return HystrixCommand.Setter
                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
                .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey))
                .andCommandPropertiesDefaults(
                        initHystrixCommandPropertiesSetter(target));
    }

    private HystrixCommandProperties.Setter initHystrixCommandPropertiesSetter(Target<?> target) {
        HystrixCommandProperties.Setter setter = HystrixCommandProperties.Setter();
        Boolean circuitBreakerEnabled = getHystrixCommandBooleanPropValue(target.name(), "circuitBreaker.enabled");
        Optional.ofNullable(circuitBreakerEnabled).ifPresent(v -> setter.withCircuitBreakerEnabled(v));
        Integer circuitBreakerRequestVolumeThreshold = getHystrixCommandIntegerPropValue(target.name(), "circuitBreaker.requestVolumeThreshold");
        Optional.ofNullable(circuitBreakerRequestVolumeThreshold).ifPresent(v -> setter.withCircuitBreakerRequestVolumeThreshold(v));
        Integer circuitBreakerSleepWindowInMilliseconds = getHystrixCommandIntegerPropValue(target.name(), "circuitBreaker.sleepWindowInMilliseconds");
        Optional.ofNullable(circuitBreakerSleepWindowInMilliseconds).ifPresent(v -> setter.withCircuitBreakerSleepWindowInMilliseconds(v));
        Integer circuitBreakerErrorThresholdPercentage = getHystrixCommandIntegerPropValue(target.name(), "circuitBreaker.errorThresholdPercentage");
        Optional.ofNullable(circuitBreakerErrorThresholdPercentage).ifPresent(v -> setter.withCircuitBreakerErrorThresholdPercentage(v));
        Boolean circuitBreakerForceOpen = getHystrixCommandBooleanPropValue(target.name(), "circuitBreaker.forceOpen");
        Optional.ofNullable(circuitBreakerForceOpen).ifPresent(v -> setter.withCircuitBreakerForceOpen(v));
        Boolean circuitBreakerForceClosed = getHystrixCommandBooleanPropValue(target.name(), "circuitBreaker.forceClosed");
        Optional.ofNullable(circuitBreakerForceClosed).ifPresent(v -> setter.withCircuitBreakerForceClosed(v));
        String executionIsolationStrategy = getHystrixCommandStringPropValue(target.name(), "execution.isolation.strategy");
        Optional.ofNullable(executionIsolationStrategy).ifPresent(v -> {
            try {
                setter.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.valueOf(v));
            } catch (Exception e) {
            }
        });
        Integer executionTimeoutInMilliseconds = getHystrixCommandIntegerPropValue(target.name(), "execution.isolation.thread.timeoutInMilliseconds");
        Optional.ofNullable(executionTimeoutInMilliseconds).ifPresent(v -> setter.withExecutionTimeoutInMilliseconds(v));
        Boolean executionTimeoutEnabled = getHystrixCommandBooleanPropValue(target.name(), "execution.timeout.enabled");
        Optional.ofNullable(executionTimeoutEnabled).ifPresent(v -> setter.withExecutionTimeoutEnabled(v));

        Boolean executionIsolationThreadInterruptOnTimeout = getHystrixCommandBooleanPropValue(target.name(), "execution.isolation.thread.interruptOnTimeout");
        Optional.ofNullable(executionIsolationThreadInterruptOnTimeout).ifPresent(v -> setter.withExecutionIsolationThreadInterruptOnTimeout(v));
        Boolean executionIsolationThreadInterruptOnFutureCancel = getHystrixCommandBooleanPropValue(target.name(), "execution.isolation.thread.interruptOnFutureCancel");
        Optional.ofNullable(executionIsolationThreadInterruptOnFutureCancel).ifPresent(v -> setter.withExecutionIsolationThreadInterruptOnFutureCancel(v));
        Integer executionIsolationSemaphoreMaxConcurrentRequests = getHystrixCommandIntegerPropValue(target.name(), "execution.isolation.semaphore.maxConcurrentRequests");
        Optional.ofNullable(executionIsolationSemaphoreMaxConcurrentRequests).ifPresent(v -> setter.withExecutionIsolationSemaphoreMaxConcurrentRequests(v));
        Integer fallbackIsolationSemaphoreMaxConcurrentRequests = getHystrixCommandIntegerPropValue(target.name(), "fallback.isolation.semaphore.maxConcurrentRequests");
        Optional.ofNullable(fallbackIsolationSemaphoreMaxConcurrentRequests).ifPresent(v -> setter.withFallbackIsolationSemaphoreMaxConcurrentRequests(v));
        Boolean fallbackEnabled = getHystrixCommandBooleanPropValue(target.name(), "fallback.enabled");
        Optional.ofNullable(fallbackEnabled).ifPresent(v -> setter.withFallbackEnabled(v));
        Integer metricsRollingStatisticalWindowInMilliseconds = getHystrixCommandIntegerPropValue(target.name(), "metrics.rollingStats.timeInMilliseconds");
        Optional.ofNullable(metricsRollingStatisticalWindowInMilliseconds).ifPresent(v -> setter.withMetricsRollingStatisticalWindowInMilliseconds(v));
        Integer metricsRollingStatisticalWindowBuckets = getHystrixCommandIntegerPropValue(target.name(), "metrics.rollingStats.numBuckets");
        Optional.ofNullable(metricsRollingStatisticalWindowBuckets).ifPresent(v -> setter.withMetricsRollingStatisticalWindowBuckets(v));
        Boolean metricsRollingPercentileEnabled = getHystrixCommandBooleanPropValue(target.name(), "metrics.rollingPercentile.enabled");
        Optional.ofNullable(metricsRollingPercentileEnabled).ifPresent(v -> setter.withMetricsRollingPercentileEnabled(v));

        Integer metricsRollingPercentileWindowInMilliseconds = getHystrixCommandIntegerPropValue(target.name(), "metrics.rollingPercentile.timeInMilliseconds");
        Optional.ofNullable(metricsRollingPercentileWindowInMilliseconds).ifPresent(v -> setter.withMetricsRollingPercentileWindowInMilliseconds(v));
        Integer metricsRollingPercentileWindowBuckets = getHystrixCommandIntegerPropValue(target.name(), "metrics.rollingPercentile.numBuckets");
        Optional.ofNullable(metricsRollingPercentileWindowBuckets).ifPresent(v -> setter.withMetricsRollingPercentileWindowBuckets(v));

        Integer metricsRollingPercentileBucketSize = getHystrixCommandIntegerPropValue(target.name(), "metrics.rollingPercentile.bucketSize");
        Optional.ofNullable(metricsRollingPercentileBucketSize).ifPresent(v -> setter.withMetricsRollingPercentileBucketSize(v));

        Integer metricsHealthSnapshotIntervalInMilliseconds = getHystrixCommandIntegerPropValue(target.name(), "metrics.healthSnapshot.intervalInMilliseconds");
        Optional.ofNullable(metricsHealthSnapshotIntervalInMilliseconds).ifPresent(v -> setter.withMetricsHealthSnapshotIntervalInMilliseconds(v));

        Boolean requestCacheEnabled = getHystrixCommandBooleanPropValue(target.name(), "requestCache.enabled");
        Optional.ofNullable(requestCacheEnabled).ifPresent(v -> setter.withRequestCacheEnabled(v));

        Boolean requestLogEnabled = getHystrixCommandBooleanPropValue(target.name(), "requestLog.enabled");
        Optional.ofNullable(requestLogEnabled).ifPresent(v -> setter.withRequestLogEnabled(v));
        return setter;
    }


    private String getHystrixCommandStringPropValue(String key, String instanceProperty) {
        return getHystrixCommandStringPropValue(key, instanceProperty, null);
    }

    private Boolean getHystrixCommandBooleanPropValue(String key, String instanceProperty) {
        return getHystrixCommandBooleanPropValue(key, instanceProperty, null);
    }

    private Integer getHystrixCommandIntegerPropValue(String key, String instanceProperty) {
        return getHystrixCommandIntegerPropValue(key, instanceProperty, null);
    }

    private String getHystrixCommandStringPropValue(String key, String instanceProperty, String defaultValue) {
        return getHystrixCommandPropValue(key, instanceProperty, defaultValue, String.class);
    }

    private Boolean getHystrixCommandBooleanPropValue(String key, String instanceProperty, Boolean defaultValue) {
        return getHystrixCommandPropValue(key, instanceProperty, defaultValue, Boolean.class);
    }

    private Integer getHystrixCommandIntegerPropValue(String key, String instanceProperty, Integer defaultValue) {
        return getHystrixCommandPropValue(key, instanceProperty, defaultValue, Integer.class);
    }

    private <T> T getHystrixCommandPropValue(String key, String instanceProperty, T defaultValue, Class<T> type) {
        return getPropValue(HYSTRIX_COMMAND_PREFIX, key, instanceProperty, defaultValue, type);
    }


    private <T> T getPropValue(String propertyPrefix, String key, String instanceProperty, T defaultValue, Class<T> type) {
        String propName = new StringBuilder()
                .append(propertyPrefix)
                .append(".")
                .append(key)
                .append(".")
                .append(instanceProperty)
                .toString();
        T value =  environment.getProperty(propName, type);
        if(value==null){
            value = defaultValue;
        }
        return value;
    }
}

yaml 配配置

hystrix:
  command:
    "Client1#getTest3(String)": # FeignClient方法級
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 100
    client-1: # FeignClient級
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1500
    default:  #所有使用Feign的service
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章