zoukankan      html  css  js  c++  java
  • Spring Cloud @HystrixCommand和@CacheResult注解使用,参数配置

      使用Spring Cloud时绕不开Hystrix,他帮助微服务实现断路器功能。该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备服务降级,服务熔断,线程和信号隔离,请求缓存,请求合并以及服务监控等强大功能。

      关于Hystrix的介绍请参见:http://www.sohu.com/a/131568369_494947,本文部分介绍引自此文,建议先阅读此文了解Hystrix的使用场景和线程池概念。

      @HystrixCommand的基础介绍请参见:http://blog.csdn.net/forezp/article/details/69934399,介绍的很详细,我这里主要说一说这个注解的各个参数的使用。

      查看com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand的源代码如下:

    /**
     * Copyright 2012 Netflix, Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package com.netflix.hystrix.contrib.javanica.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    
    /**
     * This annotation used to specify some methods which should be processes as hystrix commands.
     */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface HystrixCommand {
    
        /**
         * The command group key is used for grouping together commands such as for reporting,
         * alerting, dashboards or team/library ownership.
         * <p/>
         * default => the runtime class name of annotated method
         *
         * @return group key
         */
        String groupKey() default "";
    
        /**
         * Hystrix command key.
         * <p/>
         * default => the name of annotated method. for example:
         * <code>
         *     ...
         *     @HystrixCommand
         *     public User getUserById(...)
         *     ...
         *     the command name will be: 'getUserById'
         * </code>
         *
         * @return command key
         */
        String commandKey() default "";
    
        /**
         * The thread-pool key is used to represent a
         * HystrixThreadPool for monitoring, metrics publishing, caching and other such uses.
         *
         * @return thread pool key
         */
        String threadPoolKey() default "";
    
        /**
         * Specifies a method to process fallback logic.
         * A fallback method should be defined in the same class where is HystrixCommand.
         * Also a fallback method should have same signature to a method which was invoked as hystrix command.
         * for example:
         * <code>
         *      @HystrixCommand(fallbackMethod = "getByIdFallback")
         *      public String getById(String id) {...}
         *
         *      private String getByIdFallback(String id) {...}
         * </code>
         * Also a fallback method can be annotated with {@link HystrixCommand}
         * <p/>
         * default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()}
         *
         * @return method name
         */
        String fallbackMethod() default "";
    
        /**
         * Specifies command properties.
         *
         * @return command properties
         */
        HystrixProperty[] commandProperties() default {};
    
        /**
         * Specifies thread pool properties.
         *
         * @return thread pool properties
         */
        HystrixProperty[] threadPoolProperties() default {};
    
        /**
         * Defines exceptions which should be ignored.
         * Optionally these can be wrapped in HystrixRuntimeException if raiseHystrixExceptions contains RUNTIME_EXCEPTION.
         *
         * @return exceptions to ignore
         */
        Class<? extends Throwable>[] ignoreExceptions() default {};
    
        /**
         * Specifies the mode that should be used to execute hystrix observable command.
         * For more information see {@link ObservableExecutionMode}.
         *
         * @return observable execution mode
         */
        ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;
    
        /**
         * When includes RUNTIME_EXCEPTION, any exceptions that are not ignored are wrapped in HystrixRuntimeException.
         *
         * @return exceptions to wrap
         */
        HystrixException[] raiseHystrixExceptions() default {};
    
        /**
         * Specifies default fallback method for the command. If both {@link #fallbackMethod} and {@link #defaultFallback}
         * methods are specified then specific one is used.
         * note: default fallback method cannot have parameters, return type should be compatible with command return type.
         *
         * @return the name of default fallback method
         */
        String defaultFallback() default "";
    }

      让我们来看一下这个注解的简单应用:

    package com.example.demo.service;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    
    @Service
    public class ConsumerService {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @HystrixCommand(commandKey = "testCommand", groupKey = "testGroup", threadPoolKey = "testThreadKey",
                fallbackMethod = "hiConsumerFallBack", ignoreExceptions = {NullPointerException.class},
                threadPoolProperties = {
                        @HystrixProperty(name = "coreSize", value = "30"),
                        @HystrixProperty(name = "maxQueueSize", value = "101"),
                        @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
                        @HystrixProperty(name = "queueSizeRejectionThreshold", value = "15"),
                        @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
                        @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
                }
                )
        public String hiConsumer(String id) {
            
            //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
            return restTemplate.getForEntity("http://SERVICE_HI/hi", String.class).getBody();
        }
        
        public String hiConsumerFallBack(String id, Throwable e) {
            return "This is a error";
        }
    
    }

      

      让我们来逐个介绍下@HystrixCommand注解的各个参数:

      1:commandKey:配置全局唯一标识服务的名称,比如,库存系统有一个获取库存服务,那么就可以为这个服务起一个名字来唯一识别该服务,如果不配置,则默认是@HystrixCommand注解修饰的函数的函数名。

      2:groupKey:一个比较重要的注解,配置全局唯一标识服务分组的名称,比如,库存系统就是一个服务分组。通过设置分组,Hystrix会根据组来组织和统计命令的告、仪表盘等信息。Hystrix命令默认的线程划分也是根据命令组来实现。默认情况下,Hystrix会让相同组名的命令使用同一个线程池,所以我们需要在创建Hystrix命令时为其指定命令组来实现默认的线程池划分。此外,Hystrix还提供了通过设置threadPoolKey来对线程池进行设置。建议最好设置该参数,使用threadPoolKey来控制线程池组。

      3:threadPoolKey:对线程池进行设定,细粒度的配置,相当于对单个服务的线程池信息进行设置,也可多个服务设置同一个threadPoolKey构成线程组。

      4:fallbackMethod:@HystrixCommand注解修饰的函数的回调函数,@HystrixCommand修饰的函数必须和这个回调函数定义在同一个类中,因为定义在了同一个类中,所以fackback method可以是public/private均可。

      5:commandProperties:配置该命令的一些参数,如executionIsolationStrategy配置执行隔离策略,默认是使用线程隔离,此处我们配置为THREAD,即线程池隔离。参见:com.netflix.hystrix.HystrixCommandProperties中各个参数的定义。

      6:threadPoolProperties:线程池相关参数设置,具体可以设置哪些参数请见:com.netflix.hystrix.HystrixThreadPoolProperties
      7:ignoreExceptions:调用服务时,除了HystrixBadRequestException之外,其他@HystrixCommand修饰的函数抛出的异常均会被Hystrix认为命令执行失败而触发服务降级的处理逻辑(调用fallbackMethod指定的回调函数),所以当需要在命令执行中抛出不触发降级的异常时来使用它,通过这个参数指定,哪些异常抛出时不触发降级(不去调用fallbackMethod),而是将异常向上抛出。
      8:observableExecutionMode:定义hystrix observable command的模式;
          9:raiseHystrixExceptions:任何不可忽略的异常都包含在HystrixRuntimeException中;
          10:defaultFallback:默认的回调函数,该函数的函数体不能有入参,返回值类型与@HystrixCommand修饰的函数体的返回值一致。如果指定了fallbackMethod,则fallbackMethod优先级更高。

    请求缓存功能:
     
    注解
    描述
    属性
    @CacheResult
    该注解用来标记请求命令返回的结果应该被缓存,它必须与@HystrixCommand注解结合使用
    cacheKeyMethod
    @CacheRemove
    该注解用来让请求命令的缓存失效,失效的缓存根据定义Key决定
    commandKey,
    cacheKeyMethod
    @CacheKey
    该注解用来在请求命令的参数上标记,使其作为缓存的Key值,如果没有标注则会使用所有参数。如果同事还是使用了@CacheResult和@CacheRemove注解的cacheKeyMethod方法指定缓存Key的生成,那么该注解将不会起作用
    value
     
     
    开启请求缓存功能:
     
        开启请求缓存功能需要使用注解@CacheResult,该注解源码如下:
    /**
    * Copyright 2015 Netflix, Inc.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package com.netflix.hystrix.contrib.javanica.cache.annotation;
     
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    /**
    * Marks a methods that results should be cached for a Hystrix command.
    * This annotation must be used in conjunction with {@link com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand} annotation.
    *
    * @author dmgcodevil
    */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface CacheResult {
     
        /**
         * Method name to be used to get a key for request caching.
         * The command and cache key method should be placed in the same class and have same method signature except
         * cache key method return type, that should be <code>String</code>.
         * <p/>
         * cacheKeyMethod has higher priority than an arguments of a method, that means what actual arguments
         * of a method that annotated with {@link CacheResult} will not be used to generate cache key, instead specified
         * cacheKeyMethod fully assigns to itself responsibility for cache key generation.
         * By default this returns empty string which means "do not use cache method".
         *
         * @return method name or empty string
         */
        String cacheKeyMethod() default "";
    }
     
     
    从类签名上看,该注解标记结果需要被缓存,并且这个注解需要结合@HystrixCommand注解一起使用。该注解有一个参数cacheKeyMethod,用来指定获取cacheKey的方法名。Hystrix会根据获取到的cacheKey值来区分是否是重复请求,如果他们的cacheKey相同,那么该依赖服务只会在第一个请求到达时被真实的调用一次,另外一个请求则是直接从请求缓存中根据这个cacheKey来获取到的结果。所以开启请求缓存可以让我们实现的Hystrix命令具备下面几项好处:
    1. 减少重复的请求数,降低依赖服务的并发度;
    2. 在同一个用户请求的上下文,想同依赖服务的返回数据始终保持一致。
    3. 请求缓存在run()和contruct()执行之前生效,所以可以有效减少不必要的线程开销;    
     
    使用@CacheResult开启缓存代码示例:
    package com.example.demo;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
     
    import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult;
    import com.example.demo.entity.User;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
     
    @Service
    public class CacheResultDemo {
     
        @Autowired
        private RestTemplate restTemplate;
     
        @CacheResult(cacheKeyMethod = "getUserId")
        @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
        public User hiConsumer(String id) {
            
            //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
            return restTemplate.getForEntity("http://SERVICE_HI/hi", User.class).getBody();
        }
        
        public String hiConsumerFallBack(String id, Throwable e) {
            return "This is a error";
        }
        
        public String getUserId(String id) {
            return id;
        }
     
    }
     
    使用CacheKey开启缓存代码示例:
    package com.example.demo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    importcom.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
    import com.example.demo.entity.User;
    importcom.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    @Service
    public class CacheKeyDemo {
          @Autowired
          private RestTemplate restTemplate;
          @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
          public User hiConsumer(@CacheKey("id") String id) {
                
                //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
                return restTemplate.getForEntity("http://SERVICE_HI/hi", User.class).getBody();
          }
          
          public String hiConsumerFallBack(String id, Throwable e) {
                return "This is a error";
          }
    }
     
    其中@CacheKey除了可以指定方法参数为缓存key之外,还可以指定对象中的属性作为缓存Key,如下:
    package com.example.demo;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
     
    import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
    import com.example.demo.entity.User;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
     
    @Service
    public class CacheKeyDemo2 {
     
        @Autowired
        private RestTemplate restTemplate;
     
        @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
        public User hiConsumer(@CacheKey("id") User user) {
            
            //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
            return restTemplate.getForEntity("http://SERVICE_HI/hi", User.class, user.getId()).getBody();
        }
        
        public String hiConsumerFallBack(String id, Throwable e) {
            return "This is a error";
        }
     
    }
     
     
    清理失效缓存功能:
        使用请求缓存时,如果只是杜操作,那么不需要考虑缓存中的内容是否正确的问题,但是如果请求命令中还有更新数据的写操作,那么缓存中的数据就需要我们在进行写操作时进行及时处理,以防止读操作的请求命令获取到了失效的数据。
        通过@CacheRemove注解来实现失效缓存清理功能:
    package com.example.demo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    importcom.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey;
    importcom.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove;
    import com.example.demo.entity.User;
    importcom.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    @Service
    public class CacheRemoveDemo {
          @Autowired
          private RestTemplate restTemplate;
          @CacheRemove(commandKey = "getUserId")
          @HystrixCommand(fallbackMethod = "hiConsumerFallBack")
          public void update(@CacheKey("id") User user) {
                
                //SERVICE_HI是服务端的spring.application.name,并且大写,hi为服务端提供的接口
                restTemplate.postForObject("http://SERVICE_HI/hi", user, User.class);
                return;
          }
          
          public String hiConsumerFallBack(String id, Throwable e) {
                return "This is a error";
          }
          
          public String getUserId(String id) {
                return id;
          }
    }
  • 相关阅读:
    Android 编程下 Eclipse 恢复被删除的文件
    Android 编程下背景图片适配工具类
    Android 编程下 Managing Your App's Memory
    Android 编程下代码之(QQ消息列表滑动删除)
    Android 编程下 Canvas and Drawables
    Android 编程下 AlarmManager
    Android 编程下去除 ListView 上下边界蓝色或黄色阴影
    Java 编程下字符串的 16 位、32位 MD5 加密
    C#枚举类型和int类型相互转换
    MVC和普通三层架构的区别
  • 原文地址:https://www.cnblogs.com/wanggangblog/p/8550218.html
Copyright © 2011-2022 走看看