前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Hystrix cache 源码分析

Hystrix cache 源码分析

作者头像
java404
发布2018-08-13 17:31:19
6570
发布2018-08-13 17:31:19
举报
文章被收录于专栏:java 成神之路java 成神之路

Hystrix cache 简介

hystrix给我们提供了缓存功能,支持将一个请求结果缓存起来,下一个具有相同key的请求将直接从缓存中取出结果,减少请求开销。

要使用hystrix cache功能需要实现以下两步 1、要求是重写 getCacheKey() 方法,用来构造cache key; 2、要求是构建context,如果请求B要用到请求A的结果缓存,A和B必须同处一个context。

HystrixRequestContext

通过 HystrixRequestContext.initializeContext() 和 context.shutdown()可以构建一个context,这两条语句间的所有请求都处于同一个context。

示例

代码语言:javascript
复制
package com.jijs.cache.test;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;

/**
 * cache只有同在一个context中才生效
 * 通过HystrixRequestContext.initializeContext()初始化context,通过shutdown()关闭context
 */
public class HystrixCommandCacheTest extends HystrixCommand<Integer> {

    private final String key;
    private final int value;

    protected HystrixCommandCacheTest(String key, int value) {
        super(HystrixCommandGroupKey.Factory.asKey("RequestCacheCommandGroup"));
        this.key = key;
        this.value = value;
    }

    // 返回结果是cache的value
    @Override
    protected Integer run() {
        System.out.println("执行计算["+key+":"+value+"]");
        return value * 2;
    }

    // 构建cache的key
    @Override
    protected String getCacheKey() {
        return key + value;
    }


    public static void main(String[] args) {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        try {
            HystrixCommandCacheTest cache2a = new HystrixCommandCacheTest("cache1",2);
            HystrixCommandCacheTest cache2b = new HystrixCommandCacheTest("cache1",2);
            HystrixCommandCacheTest cache2c = new HystrixCommandCacheTest("cache2",2);

            System.out.println("结果:" + cache2a.execute() + ";是否从缓存取值:" + cache2a.isResponseFromCache());
            System.out.println("结果:" + cache2b.execute() + ";是否从缓存取值:" + cache2b.isResponseFromCache());
            System.out.println("结果:" + cache2c.execute() + ";是否从缓存取值:" + cache2c.isResponseFromCache());
        } finally {
            context.shutdown();
        }

    }
}
执行结果
代码语言:javascript
复制
执行计算[cache1:2]
结果:4;是否从缓存取值:false
结果:4;是否从缓存取值:true
执行计算[cache2:2]
结果:4;是否从缓存取值:false

从结果中可以看出 cache2a 、 cache2b 和 cache2c 都在同一个 HystrixRequestContext 上下文中。 1、当执行 cache2a 时,没有缓存,则把cache2a的执行结果缓存起来。 2、再执行 cache2b 时,发现 缓存中已经存在,则从缓存中获取,没有调用 run() 方法去计算结果。 3、执行 cache2c 时,缓存中没有该数据,则调用run() 方法进行计算返回,并把该计算结果缓存起来。

HystrixRequestContext 源码分析
代码语言:javascript
复制
public class HystrixRequestContext implements Closeable {

    private static ThreadLocal<HystrixRequestContext> requestVariables = new ThreadLocal<HystrixRequestContext>();

    public static boolean isCurrentThreadInitialized() {
        HystrixRequestContext context = requestVariables.get();
        return context != null && context.state != null;
    }

    public static HystrixRequestContext getContextForCurrentThread() {
        HystrixRequestContext context = requestVariables.get();
        if (context != null && context.state != null) {
            return context;
        } else {
            return null;
        }
    }

    public static void setContextOnCurrentThread(HystrixRequestContext state) {
        requestVariables.set(state);
    }

    public static HystrixRequestContext initializeContext() {
        HystrixRequestContext state = new HystrixRequestContext();
        requestVariables.set(state);
        return state;
    }

    ConcurrentHashMap<HystrixRequestVariableDefault<?>, HystrixRequestVariableDefault.LazyInitializer<?>> state = new ConcurrentHashMap<HystrixRequestVariableDefault<?>, HystrixRequestVariableDefault.LazyInitializer<?>>();

    private HystrixRequestContext() {

    }

    public void shutdown() {
        if (state != null) {
            for (HystrixRequestVariableDefault<?> v : state.keySet()) {
                try {
                    HystrixRequestVariableDefault.remove(this, v);
                } catch (Throwable t) {
                    HystrixRequestVariableDefault.logger.error("Error in shutdown, will continue with shutdown of other variables", t);
                }
            }

            state = null;
        }
    }

    public void close() {
      shutdown();
    }

}

从代码中可以看出,HystrixRequestContext 使用了 ThreadLocal 进行存储。也就是说,缓存的范围是线程隔离的,当前线程缓存的数据,只能在当前线程中使用。线程销毁则缓存自动失效。 如果执行 HystrixRequestContext.shutdown() 或者 close() 方法时,缓存也会失效。

缓存核心源码分析

1、首先调用 isRequestCachingEnabled() 方法判断是否开启 cache 功能。

2、如果开启,则通过 我们自己重写的 getCacheKey() 方法获取,要冲缓冲获取的 cacheKey。

代码语言:javascript
复制
public abstract class HystrixCommand<R> extends AbstractCommand<R> 
    implements HystrixExecutable<R>, HystrixInvokableInfo<R>, HystrixObservable<R> 

从代码中可以看到 HystrixCommand 实现了 AbstractCommand 类,所以 getCacheKey() 就是我们重写的方法。

3、从 requestCache.get() 方法中获取缓存数据。

判断是否开启缓存

代码语言:javascript
复制
protected boolean isRequestCachingEnabled() {
    return properties.requestCacheEnabled().get() && getCacheKey() != null;
}

首先判断 HystrixCommandProperties.Setter().withRequestCacheEnabled(boolean value) 是否指定了开启缓存 然后在判断 是否重写了 getCacheKey() 方法,并且重写 getCacheKey() 方法返回值不能为 null。

获取缓存数据

从 HystrixRequestCache中获取缓存数据, 调用 requestCache.get() 方法获取。 HystrixRequestCache 类中使用了 ConcurrentHashMap ,根据 key、value 进行缓存执行的结果。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.07.29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Hystrix cache 简介
    • HystrixRequestContext
    • 示例
      • 执行结果
        • HystrixRequestContext 源码分析
          • 缓存核心源码分析
          • 判断是否开启缓存
          • 获取缓存数据
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档