91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

詳解feign調用session丟失解決方案

發布時間:2020-10-15 10:12:24 來源:腳本之家 閱讀:244 作者:zl1zl2zl3 欄目:編程語言

最近在做項目的時候發現,微服務使用feign相互之間調用時,存在session丟失的問題。例如,使用Feign調用某個遠程API,這個遠程API需要傳遞一個鑒權信息,我們可以把cookie里面的session信息放到Header里面,這個Header是動態的,跟你的HttpRequest相關,我們選擇編寫一個攔截器來實現Header的傳遞,也就是需要實現RequestInterceptor接口,具體代碼如下:

@Configuration 
@EnableFeignClients(basePackages = "com.xxx.xxx.client") 
public class FeignClientsConfigurationCustom implements RequestInterceptor { 
 
 @Override 
 public void apply(RequestTemplate template) { 
 
  RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); 
  if (requestAttributes == null) { 
   return; 
  } 
 
  HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); 
  Enumeration<String> headerNames = request.getHeaderNames(); 
  if (headerNames != null) { 
   while (headerNames.hasMoreElements()) { 
    String name = headerNames.nextElement(); 
    Enumeration<String> values = request.getHeaders(name); 
    while (values.hasMoreElements()) { 
     String value = values.nextElement(); 
     template.header(name, value); 
    } 
   } 
  } 
 
 } 
 
} 

經過測試,上面的解決方案可以正常的使用; 

但是,當引入Hystrix熔斷策略時,出現了一個新的問題:

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

此時requestAttributes會返回null,從而無法傳遞session信息,最終發現RequestContextHolder.getRequestAttributes(),該方法是從ThreadLocal變量里面取得對應信息的,這就找到問題原因了,是由于Hystrix熔斷機制導致的。 
Hystrix有2個隔離策略:THREAD以及SEMAPHORE,當隔離策略為 THREAD 時,是沒辦法拿到 ThreadLocal 中的值的。

因此有兩種解決方案:

方案一:調整格隔離策略:

hystrix.command.default.execution.isolation.strategy: SEMAPHORE

這樣配置后,Feign可以正常工作。

但該方案不是特別好。原因是Hystrix官方強烈建議使用THREAD作為隔離策略! 可以參考官方文檔說明。

方案二:自定義策略

記得之前在研究zipkin日志追蹤的時候,看到過Sleuth有自己的熔斷機制,用來在thread之間傳遞Trace信息,Sleuth是可以拿到自己上下文信息的,查看源碼找到了 
org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixConcurrencyStrategy 
這個類,查看SleuthHystrixConcurrencyStrategy的源碼,繼承了HystrixConcurrencyStrategy,用來實現了自己的并發策略。

/**
 * Abstract class for defining different behavior or implementations for concurrency related aspects of the system with default implementations.
 * <p>
 * For example, every {@link Callable} executed by {@link HystrixCommand} will call {@link #wrapCallable(Callable)} to give a chance for custom implementations to decorate the {@link Callable} with
 * additional behavior.
 * <p>
 * When you implement a concrete {@link HystrixConcurrencyStrategy}, you should make the strategy idempotent w.r.t ThreadLocals.
 * Since the usage of threads by Hystrix is internal, Hystrix does not attempt to apply the strategy in an idempotent way.
 * Instead, you should write your strategy to work idempotently. See https://github.com/Netflix/Hystrix/issues/351 for a more detailed discussion.
 * <p>
 * See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a
 *  rel="external nofollow" >https://github.com/Netflix/Hystrix/wiki/Plugins</a>.
 */
public abstract class HystrixConcurrencyStrategy 

搜索發現有好幾個地方繼承了HystrixConcurrencyStrategy類 

詳解feign調用session丟失解決方案

其中就有我們熟悉的Spring Security和剛才提到的Sleuth都是使用了自定義的策略,同時由于Hystrix只允許有一個并發策略,因此為了不影響Spring Security和Sleuth,我們可以參考他們的策略實現自己的策略,大致思路: 

將現有的并發策略作為新并發策略的成員變量; 

在新并發策略中,返回現有并發策略的線程池、Queue; 

代碼如下:

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

最后,將這個策略類作為bean配置到feign的配置類FeignClientsConfigurationCustom中

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

至此,結合FeignClientsConfigurationCustom配置feign調用session丟失的問題完美解決。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。 

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

西安市| 公主岭市| 金川县| 盐边县| 芒康县| 莒南县| 凭祥市| 云安县| 清水县| 环江| 盖州市| 潜山县| 梅州市| 桐乡市| 徐汇区| 敦化市| 郧西县| 建昌县| 上饶市| 湖州市| 同德县| 松潘县| 舒城县| 玉环县| 托里县| 合川市| 颍上县| 安义县| 乌什县| 娱乐| 虎林市| 嵊泗县| 集贤县| 阿拉善盟| 阿尔山市| 嫩江县| 康保县| 泰宁县| 科技| 普格县| 山东省|