• 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;
          }
    }
  • 相关阅读:
    flask 第三方组件
    Flask基础与进阶
    odoo10 视图
    odoo10 ORM操作
    odoo10基础
    字典的setdefault方法
    redis常用操作
    git常用命令与操作
    vue_axios
    odoo 权限设置
  • 原文地址:https://www.cnblogs.com/wanggangblog/p/8550218.html
Copyright © 2020-2023  润新知