zoukankan      html  css  js  c++  java
  • Hystrix-request cache(请求缓存)

    开启请求缓存

      请求缓存在run()和construce()执行之前生效,所以可以有效减少不必要的线程开销。你可以通过实现getCachekey()方法来开启请求缓存。

    package org.hope.hystrix.example.request.cache;
    
    import com.netflix.hystrix.HystrixCommand;
    import com.netflix.hystrix.HystrixCommandGroupKey;
    
    public class CommandUsingRequestCache extends HystrixCommand<Boolean> {
        private final int value;
    
        public CommandUsingRequestCache(int value) {
            super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
            this.value = value;
        }
    
        @Override
        protected Boolean run() throws Exception {
            return value == 0 || value % 2 == 0;
        }
    
        @Override
        protected String getCacheKey() {
            return String.valueOf(value);
        }
    }

    单元测试

    package org.hope.hystrix.example.request.cache;
    
    import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
    import org.hope.hystrix.example.request.cache.CommandUsingRequestCache;
    import org.junit.Test;
    
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertFalse;
    import static org.junit.Assert.assertTrue;
    
    public class CommandUsingRequestCacheTest {
    
        @Test
        public void testWithoutCacheHits() {
            HystrixRequestContext cxt = HystrixRequestContext.initializeContext();
            try {
                assertTrue(new CommandUsingRequestCache(2).execute());
                assertTrue(new CommandUsingRequestCache(1).execute());
            } finally {
                cxt.shutdown();
            }
        }
    
        @Test
        public void testWithCacheHits() {
            HystrixRequestContext cxt = HystrixRequestContext.initializeContext();
            try {
                CommandUsingRequestCache command2a = new CommandUsingRequestCache(2);
                CommandUsingRequestCache command2b = new CommandUsingRequestCache(2);
    
                assertTrue(command2a.execute());
                // this is the first time we've executed this command with the value of "2" so it should not be from cache
    //            assertFalse(command2a.isResponseFromCache());
                System.out.println(command2a.isResponseFromCache());
    
                assertTrue(command2b.execute());
                // this is the second time we've executed this command with the same value so it should return from cache
    //            assertTrue(command2b.isResponseFromCache());
                System.out.println(command2b.isResponseFromCache());
            } finally {
                cxt.shutdown();
            }
    
            // start a new request context
            cxt = HystrixRequestContext.initializeContext();
            try {
                CommandUsingRequestCache command3b = new CommandUsingRequestCache(2);
                assertTrue(command3b.execute());
                // this is a new request context so this should not come from cache
    //            assertFalse(command3b.isResponseFromCache());
                System.out.println(command3b.isResponseFromCache());
            } finally {
                cxt.shutdown();
            }
        }
    }

    清理失效缓存

    package org.hope.hystrix.example.request.cache;
    
    
    import com.netflix.hystrix.HystrixCommand;
    import com.netflix.hystrix.HystrixCommandGroupKey;
    import com.netflix.hystrix.HystrixCommandKey;
    import com.netflix.hystrix.HystrixRequestCache;
    import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault;
    
    /**
     * 清理缓存
     */
    public class CommandUsingRequestCacheInvalidation{
    
        private static volatile String prefixStoredOnRemoteDataStore = "ValueBeforeSet_";
    
        public static class GetterCommand extends HystrixCommand<String> {
            private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("GetterCommand");
            private final int id;
            public GetterCommand(int id) {
                super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetSetGet")).andCommandKey(GETTER_KEY));
                this.id = id;
            }
    
            @Override
            protected String run() throws Exception {
                return prefixStoredOnRemoteDataStore + id;
            }
    
            @Override
            protected String getCacheKey() {
                return String.valueOf(id);
            }
    
            //Allow the cache to be flushed for this object.
            public static void flushCache(int id) {
                HystrixRequestCache.getInstance(GETTER_KEY, HystrixConcurrencyStrategyDefault.getInstance()).clear(String.valueOf(id));
            }
    
        }
    
        public static class SetterCommand extends HystrixCommand<Void> {
            private final int id;
            private final String prefix;
    
            public SetterCommand(int id, String prefix) {
                super(HystrixCommandGroupKey.Factory.asKey("GetSetGet"));
                this.id = id;
                this.prefix = prefix;
            }
    
    
            @Override
            protected Void run() throws Exception {
                // persist the value against the datastore
                prefixStoredOnRemoteDataStore = prefix;
                // flush the cache
                GetterCommand.flushCache(id);
                return null;
            }
        }
    
    }

    单元测试:

    package org.hope.hystrix.example.request.cache;
    
    import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
    import org.junit.Test;
    
    /**
     * Created by lisen on 2017/12/27.
     */
    public class CommandUsingRequestCacheInvalidationTest {
    
        @Test
        public void flushCacheTest() {
            HystrixRequestContext context = HystrixRequestContext.initializeContext();
            System.out.println(new CommandUsingRequestCacheInvalidation.GetterCommand(1).execute());
    
            CommandUsingRequestCacheInvalidation.GetterCommand commandAgainstCache = new CommandUsingRequestCacheInvalidation.GetterCommand(1);
    
            System.out.println(commandAgainstCache.isResponseFromCache()); //false
            System.out.println(commandAgainstCache.execute());
            System.out.println(commandAgainstCache.isResponseFromCache()); //false
            // set the new value
            new CommandUsingRequestCacheInvalidation.SetterCommand(1, "ValueAfterSet_").execute();
            // fetch it again
            CommandUsingRequestCacheInvalidation.GetterCommand commandAfterSet = new CommandUsingRequestCacheInvalidation.GetterCommand(1);
            //the getter should return with the new prefix, not the value from cache
            System.out.println(commandAfterSet.isResponseFromCache());
            System.out.println(commandAfterSet.execute());
        }
    }

    注解的实现请求缓存

    注解 描述 属性
    @CacheResult 改注解用来标记请求命令返回的结果应该被缓存,它必须与@HystrixCommand注解结合使用 cacheKeyMethod
    @CacheRemove 该注解用来让请求命令的缓存失效,失效的缓存根据定义的key决定 commandKey,cacheKeyMethod
    @CacheKey

    改注解用来在请求命令的参数上标记,使其作为缓存的Key值,如果没有标注则会使用所有参数。如果同时还使用了@CacheResult和

    @CacheRemove注解的cacheKeyMethod方法指定缓存Key的生成,那么该注解将不会起作用

    value

    设置缓存

    package org.hope.hystrix.example.request.cache;
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
    import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
    import org.hope.hystrix.example.model.User;
    import org.springframework.stereotype.Service;
    @Service public class RequestCacheAnnotation { /** * 返回的结果会置入请求缓存中,缓存的key值会使用所有的方法入参, * 也就是这里Long类型的id */ @CacheResult @HystrixCommand public String getUserById(Long id) { return "你好" + id; } /** * cacheKeyMethod可以为缓存指定具体的缓存key */ @CacheResult(cacheKeyMethod = "getUserByIdCacheKey") @HystrixCommand public String getUserById2(Long id) { return "你好:" + id; } public String getUserByIdCacheKey(Long id) { return String.valueOf(id); } /** * 通过@CacheKey来定义具体的缓存Key。 * 但是注意,@CacheKey的优先级比@CacheResult(cacheKeyMethod = "")的优先级低。 * 如果已经使用了cacheKeyMethod指定缓存Key的生成函数,那么@CacheKey注解不会生效 */ @CacheResult @HystrixCommand public String getUserById3(@CacheKey("id") Long id) { return "你好:" + id; } /** * @CacheKey还可以通过访问参数对象内部属性作为缓存key * 这里指定了User对象id属性作为缓存key */ @CacheResult @HystrixCommand public String getUserById4(@CacheKey("id") User user) { return "你好" + user.getId(); } }

    清理缓存

    package org.hope.hystrix.example.request.cache;
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
    import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
    import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
    import org.hope.hystrix.example.model.User;
    
    public class RequestClearCacheAnnotation {
    
        @CacheResult
        @HystrixCommand
        public User getUserById(@CacheKey("id") Long id) {
            User u = new User();
            u.setId(id);
            return u;
        }
    
        /**
         * 用@CacheRemove来清理失效缓存,其中commandKey是必须指定的
         */
        @CacheRemove(commandKey = "getUserById")
        @HystrixCommand
        public void update(@CacheKey("id") User user) {
            User u = new User();
            u.setId(20L);
        }
    
        public String getUserById(User user) {
            return String.valueOf(user.getId());
        }
    }

    https://gitee.com/huayicompany/Hystrix-learn/tree/master/hystrix-example

    参考:

    [1]Github,https://github.com/Netflix/Hystrix/wiki/How-it-Works

    [2] 《SpringCloud微服务实战》,电子工业出版社,翟永超

  • 相关阅读:
    Spring基础知识点总结
    秒懂设计模式--代理模式(proxy)
    秒懂设计模式--工厂模式
    秒懂设计模式--适配器模式
    秒懂设计模式--装饰者模式
    秒懂设计模式--观察者模式
    单例模式的几种实现
    springboot2.0+spring cloud+eureka搭建微服务步骤
    字符串排序算法
    bitbucket的简单使用
  • 原文地址:https://www.cnblogs.com/happyflyingpig/p/8119754.html
Copyright © 2011-2022 走看看