fegin+hystrix中Request Contect Holder.get Request Attributesを解決します.null値を返す解決方法


ヤンキーの記事を転載: http://www.itmuch.com/spring-cloud-sum/hystrix-threadlocal/カスタムfeignスクリーンショット 
package com.wm.commonfeign.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @class_name: CustomFeignConfig
 * @description:        authorization   ,       
 * @author: wm_yu
 * @create: 2019/07/26
 **/
@Configuration
@Slf4j
public class CustomFeignConfig implements RequestInterceptor {
    private static final String TOKEN_HEADER = "authorization";

    @Override
    public void apply(RequestTemplate requestTemplate) {
        HttpServletRequest request = getHttpServletRequest();
        //       TODO           RequestInterceptor      request    ,            ,   ,    feign       
        String jsonString = this.getRequestJsonString(request);
        //    feign  
        log.info("feign          ,methodName={},Parameter={}",request.getMethod(),jsonString);
        if (ObjectUtils.isEmpty(request)) {
            requestTemplate.header(TOKEN_HEADER, getHeaders(request).get(TOKEN_HEADER));
        }
    }


    /**
     *      request
     * @return
     */
    private HttpServletRequest getHttpServletRequest() {
        try {
            // hystrix       RequestContextHolder.getRequestAttributes()  null
            //     :http://www.itmuch.com/spring-cloud-sum/hystrix-threadlocal/
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (!ObjectUtils.isEmpty(attributes)){
                return attributes.getRequest();
            }
            return null;
        } catch (Exception e) {
            log.error("feign      HttpServletRequest error...",e.getMessage(),e);
            return null;
        }
    }

    /**
     *      header    
     * @param request
     * @return
     */
    private Map getHeaders(HttpServletRequest request) {
        Map map = new LinkedHashMap<>();
        Enumeration enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return map;
    }


    /**
     *   request  json  
     * @param request
     * @return
     */
    public  String getRequestJsonString(HttpServletRequest request){
        try {

            int contentLength = request.getContentLength();
            if (contentLength < 0) {
                return null;
            }
            byte buffer[] = new byte[contentLength];
            for (int i = 0; i < contentLength;) {
                int readlen = request.getInputStream().read(buffer, i, contentLength - i);
                if (readlen == -1) {
                    break;
                }
                i += readlen;
            }

            String charEncoding = request.getCharacterEncoding();
            if (charEncoding == null) {
                charEncoding = "UTF-8";
            }
            return new String(buffer, charEncoding);
        } catch (Exception e) {
            log.error("  request     ....",e.getMessage(),e);
        }
        return null;
    }


}
 
解决fegin+hystrix中RequestContextHolder.getRequestAttributes();返回null值的解决方法_第1张图片
 
途中コードでnullに戻ります.
解決方法:ユーザー定義のヒューズポリシー
package com.wm.commonfeign.strategy;

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 lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
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;

/**
 * @class_name: CustomFeignHystrixConcurrencyStrategy
 * @description:           RequestContextHolder.getRequestAttributes()    null
 * @author: wm_yu
 * @create: 2019/07/26
 **/
@Component
@Primary
@Slf4j
public class CustomFeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy{

    private HystrixConcurrencyStrategy hystrixConcurrencyStrategy;

    public CustomFeignHystrixConcurrencyStrategy() {
        try {
            this.hystrixConcurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (this.hystrixConcurrencyStrategy instanceof CustomFeignHystrixConcurrencyStrategy) {
                // 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.hystrixConcurrencyStrategy + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
                    + metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
            log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
        }
    }

    @Override
    public  Callable wrapCallable(Callable callable) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return new WrappedCallable<>(callable, requestAttributes);
    }

    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixProperty corePoolSize, HystrixProperty maximumPoolSize,
                                            HystrixProperty keepAliveTime, TimeUnit unit, BlockingQueue workQueue) {
        return this.hystrixConcurrencyStrategy.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
                unit, workQueue);
    }

    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixThreadPoolProperties threadPoolProperties) {
        return this.hystrixConcurrencyStrategy.getThreadPool(threadPoolKey, threadPoolProperties);
    }

    @Override
    public BlockingQueue getBlockingQueue(int maxQueueSize) {
        return this.hystrixConcurrencyStrategy.getBlockingQueue(maxQueueSize);
    }

    @Override
    public  HystrixRequestVariable getRequestVariable(HystrixRequestVariableLifecycle rv) {
        return this.hystrixConcurrencyStrategy.getRequestVariable(rv);
    }

    static class WrappedCallable implements Callable {
        private final Callable target;
        private final RequestAttributes requestAttributes;

        public WrappedCallable(Callable 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();
            }
        }
    }
}
fegin対応hystrixを設定し、溶断のタイムアウトを指定します.
解决fegin+hystrix中RequestContextHolder.getRequestAttributes();返回null值的解决方法_第2张图片
 
feign:
  hystrix:
    enabled:  true

# hystrix  
hystrix:
  shareSecurityContext: true
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000
 
feignは他のサービスへの呼び出しを提供します. 
package com.wm.examapi.feign;

import com.wm.commoncore.constant.ServiceConstant;
import com.wm.commoncore.model.Response;
import com.wm.commonfeign.config.CustomFeignConfig;
import com.wm.examapi.feign.fallback.ExaminationServiceClientFallbackImpl;
import com.wm.examapi.model.Examination;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @class_name: ExaminationServiceClient
 * @description:      .... FeignClient    configuration CustomFeignConfig,         token
 * @author: wm_yu
 * @create: 2019/07/26
 **/
@FeignClient(name = ServiceConstant.EXAM_SERVICE, configuration = CustomFeignConfig.class, fallback = ExaminationServiceClientFallbackImpl.class)
public interface ExaminationServiceClient {
    /**
     *       
     *
     * @param examination     
     * @return ResponseBean
     */
    /**
     *        RequestMapping       post,    @PostMapping
     * @param examination
     * @return
     */
    @RequestMapping(method = RequestMethod.POST,value = "/api/exam/getExaminationCount")
    Response findExaminationCount(@RequestBody Examination examination);
}
溶断類の設定:
package com.wm.examapi.feign.fallback;

import com.wm.commoncore.constant.BussiConstant;
import com.wm.commoncore.model.Response;
import com.wm.examapi.feign.ExaminationServiceClient;
import com.wm.examapi.model.Examination;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;


/**
 * @class_name: ExaminationServiceClientFallbackImpl
 * @description:        
 * @author: wm_yu
 * @create: 2019/07/26
 **/
@Slf4j
@Component
public class ExaminationServiceClientFallbackImpl implements ExaminationServiceClient {

    private Throwable throwable;

    @Override
    public Response findExaminationCount(@RequestBody Examination examination) {
        log.error("  {}  , {}, {}", "findExaminationCount", examination.getTenantCode(),throwable);
        return  Response.createError(BussiConstant.EXAM_SERVICE_FEIGN_ERROR,0);
    }

    public Throwable getThrowable() {
        return throwable;
    }

    public void setThrowable(Throwable throwable) {
        this.throwable = throwable;
    }
}
溶断工場を作成し、溶断例を生成する.
package com.wm.examapi.feign.factory;

import com.wm.examapi.feign.ExaminationServiceClient;
import com.wm.examapi.feign.fallback.ExaminationServiceClientFallbackImpl;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

/**
 * @class_name: UserServiceClientFallbackFactory
 * @description:          
 * @author: wm_yu
 * @create: 2019/07/26
 **/
@Component
public class ExaminationServiceClientFallbackFactory implements FallbackFactory {
    @Override
    public ExaminationServiceClient create(Throwable throwable) {
        ExaminationServiceClientFallbackImpl examinationServiceClientFallback = new ExaminationServiceClientFallbackImpl();
        examinationServiceClientFallback.setThrowable(throwable);
        return examinationServiceClientFallback;
    }
}
クラススキャンを開始する解决fegin+hystrix中RequestContextHolder.getRequestAttributes();返回null值的解决方法_第3张图片
package com.wm.userservice;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@SpringBootApplication
@EnableDiscoveryClient  //      
@MapperScan("com.wm.userservice.mapper")
@EnableFeignClients(basePackages = {"com.wm.examapi.feign"}) //  fegin 
@ComponentScan({"com.wm.examapi.feign","com.wm.userservice","com.wm.commonfeign"})  //            (      ), :fegin   
public class UserServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }


    /**
     *      
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }

    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }

}
ここは一つのvueを多く配置して、ドメインを越えて解決します.
 
元々はスクリーンにログ情報を出力したいですが、だめでした.これは処理します.今は個人的に理解している原因です.
解决fegin+hystrix中RequestContextHolder.getRequestAttributes();返回null值的解决方法_第4张图片
 
後は公式のfeignログで出力します.
簡単です
ログの設定クラスを作成します.
解决fegin+hystrix中RequestContextHolder.getRequestAttributes();返回null值的解决方法_第5张图片
以下のとおりです
package com.wm.commonfeign.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @class_name: FeignLogConfig
 * @description:   feign    
 * @author: wm_yu
 * @create: 2019/07/27
 **/

/**
 * Feign logging
 * A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.
 *
 *   application.yml
 *
 * logging.level.project.user.UserClient: DEBUG
 *
 *
 * The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:
 *
 *               (Logger.Level),   :
 *
 * NONE, No logging (DEFAULT).
 * BASIC, Log only the request method and URL and the response status code and execution time.
 * HEADERS, Log the basic information along with request and response headers.
 * FULL, Log the headers, body, and metadata for both requests and responses.
 * For example, the following would set the Logger.Level to FULL:
 *
 *            (FULL):
 *
 * @Configuration
 * public class FooConfiguration {
 *     @Bean
 *     Logger.Level feignLoggerLevel() {
 *         return Logger.Level.FULL;
 *     }
 * }
 */

@Configuration
public class FeignLogConfig {
        @Bean
        Logger.Level feignLoggerLevel() {
            return Logger.Level.FULL;
        }
}
コメントが削除されたのは公式文書の解釈です.
ymlに出力するログレベルと指定feignクラスを設定します.
 
logging:
  level:
    root: info
     ####sql  
    com.wm.examservice.mapper: debug
    #### feign  
    com.wm.examapi.feign: debug
 
解决fegin+hystrix中RequestContextHolder.getRequestAttributes();返回null值的解决方法_第6张图片