Request Cache 请求缓存
javanica提供特定的注解,以便启用和管理请求缓存。 这些注解看起来非常类似于JSR107,但是没不那么广泛,另一方面Hystrix不提供独立和复杂的缓存系统,因此没有必要像JSR107一样有这样的注释多样性。 Javanica只有三个专用于请求缓存的注解。
Annotation | 描述 | Properties |
---|---|---|
@CacheResult | 标记一个方法的返回结果应被缓存。此注释必须与HystrixCommand配合使用。 | cacheKeyMethod |
@CacheRemove | 标记用于使命令的高速缓存无效的方法。 生成的缓存密钥必须与在链接CacheResult上下文中生成的密钥相同 | commandKey, cacheKeyMethod |
@CacheKey | 将方法的参数标记为缓存的key。 如果没有标记参数,则使用所有参数。 如果@CacheResult或@CacheRemove annotation指定了cacheKeyMethod,那么方法参数不会用于构建缓存的key,即使它们用@CacheKey注解 | value |
cacheKeyMethod - 用于获取请求缓存的键的方法名称。 命令和缓存键方法应放在同一个类中,并且具有相同的方法签名,但缓存键方法返回类型应为String。 cacheKeyMethod具有比方法的参数更高的优先级,这意味着使用@CacheResult注释的方法的实际参数不会用于生成高速缓存密钥,而是改为指定cacheKeyMethodly分配给自己负责缓存密钥生成。 默认情况下,这返回空字符串,这意味着“不使用缓存方法。可以考虑使用cacheKeyMethod作为公共密钥生成器的替代(例如JSR170-CacheKeyGenerator),但是使用cacheKeyMethod缓存密钥生成变得更方便和简单。 比较两种方法:JSR107
( , class) update( user) { storageput(usergetId(), user); } { ( ) { cacheInvocationParameter cacheKeyInvocationContextgetKeyParameters()[]; user () cacheInvocationParametergetValue(); (usergetId()); } }
Javanica cacheKeyMethod
( , ) update( user) { storageput(usergetId(), user); } cacheKeyMethod( user) { usergetId(); }
或者直接写成这样:
( ) update(() user) { storageput(usergetId(), user); }
您不需要创建新类,如果您将为缓存键方法提供正确的名称,也可以使用cacheKeyMethod帮助重构。 建议将前缀“cacheKeyMethod”附加到实际方法名称,例如:
public User getUserById(@CacheKey String id);
private User getUserByIdCacheKeyMethod(String id);
Cache key generator
Jacanica只有一个缓存密钥生成器HystrixCacheKeyGenerator,它根据CacheInvocationContext生成一个HystrixGeneratedCacheKey。 实现是线程安全的。 注释方法的参数由以下规则选择:
如果没有用@CacheKey标记参数,则包括所有参数
如果一个或多个@CacheKey注释存在,那么只包括带有@CacheKey注解的那些参数
注意:如果CacheResult或CacheRemove注释指定了cacheKeyMethod,那么方法参数不会用于构建缓存键,即使它们用CacheKey注释。
@CacheKey和value属性此注释默认有一个属性,允许指定某个参数属性的名称。 例如:@CacheKey(“id”)用户用户或在组合属性的情况下:@CacheKey(“profile.name”)用户用户。 空属性被忽略,即如果profile为空,则@CacheKey(“profile.name”)的结果用户用户将是空字符串。
例:
getUserById( id) { storageget(id); } ( ) getUserByName( name) { storagegetByName(name); } getUserByNameCacheKey( name) { name; } getUserByProfileName(() user) { storagegetUserByProfileName(usergetProfile()getName()); }
Get-Set-Get模式要了解有关此模式的更多信息,您可以阅读本章示例:
{ ( ) { storageget(id); } ( ) (() ) { storageput(usergetId(), user); } } test(){ user userServicegetUserById(); getUserByIdCommand getLastExecutedCommand(); assertFalse(getUserByIdCommandisResponseFromCache()); user userServicegetUserById(); getUserByIdCommand getLastExecutedCommand(); assertTrue(getUserByIdCommandisResponseFromCache()); user (, ); userServiceupdate(user); user userServicegetUserById(); getUserByIdCommand getLastExecutedCommand(); assertFalse(getUserByIdCommandisResponseFromCache()); }
Note:您可以将@CacheRemove注释与@HystrixCommand结合使用或不使用。 如果你想用@CacheRemove注释注释not命令方法,那么你需要添加HystrixCacheAspect方面到你的配置:
<aspects> ... <aspect name="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCacheAspect"/> ... </aspects><!-- or Spring conf --> <aop:aspectj-autoproxy/> <bean id="hystrixAspect" class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCacheAspect"></bean>
Configuration 配置
Command Properties 命令属性
@HystrixCommand的属性应该使用commandProperties,像下面这样:
( { ( , ) }) getUserById( id) { userResourcegetUserById(id); }
Javanica使用Hystrix ConfigurationManager动态设置属性。 对于上面的例子,Javanica在幕后执行了以下动作:
getConfigInstance() setProperty(, );
ThreadPoolProperties,有关线程池的属性设置,你可以使用@HystrixCommand的threadPoolProperties,像下面这样:
( { ( , ) }, { ( , ), ( , ), ( , ), ( , ), ( , ), ( , ) }) getUserById( id) { userResourcegetUserById(id); }
DefaultProperties 默认属性
@DefaultProperties是类(类型)级别注解,允许缺省命令属性,如groupKey,threadPoolKey,commandProperties,threadPoolProperties,ignoreExceptions和raiseHystrixExceptions。 使用此注解指定的属性将默认用于在注释类中定义的每个hystrix命令,除非命令使用相应的@HystrixCommand参数显式指定这些属性。 例:
( ) { () { ; } ( ) () { ; } }
Hystrix collapser
假设你有一些命令调用需要折叠在一个后端调用中批量处理,那么你可以使用@HystrixCollapser这个注解来完成。
例:
( ) getUserByIdAsync( id) { ; } ( ) getUserByIdReact( id) { ; } getUserByIds( ids) { users (); ( id ids) { usersadd( (id, id)); } users; } f1 userServicegetUserByIdAsync(); f2 userServicegetUserByIdAsync(); f3 userServicegetUserByIdAsync(); f4 userServicegetUserByIdAsync(); f5 userServicegetUserByIdAsync(); u1 getUserByIdReact(); u2 getUserByIdReact(); u3 getUserByIdReact(); u4 getUserByIdReact(); u5 getUserByIdReact(); users merge(u1, u2, u3, u4, u5) toBlocking() toIterable();
使用@HystrixCollapser注解标记的方法可以返回具有兼容类型的任何值,它不会影响collapser方法执行的结果,collapser方法甚至可以返回null或另一个存根。 方法签名要遵循以下的原则。
Collapser方法必须有一个任何类型的参数,须是一个原始类型的包装器,如Integer,Long,String等。
批处理方法(batch method)必须有一个参数,类型为java.util.List,参数化为相应的类型,即如果collapser参数的类型为Integer,则批处理方法参数的类型必须为List <Integer>。
批处理方法的返回类型必须是java.util.List参数化为相应的类型,也就是如果collapser方法的返回类型是User然后返回类型的批处理命令必须是List <User>。
批处理方法行为约定
响应集合的大小必须等于请求集合的大小。
@HystrixCommand public List<User> getUserByIds(List<String> ids); // batch method List<String> ids = List("1", "2", "3"); getUserByIds(ids).size() == ids.size();
响应集合中的元素顺序必须与请求集合中的元素顺序相同。
@HystrixCommand public List<User> getUserByIds(List<String> ids); // batch method List<String> ids = List("1", "2", "3"); List<User> users = getUserByIds(ids); System.out.println(users); // output User: id=1 User: id=2 User: id=3
为什么要保证请求的元素顺序和响应的元素顺序一致?
原因是在减少逻辑,基本上请求元素是一对一映射到响应元素。 因此,如果请求收集的元素的顺序不同,那么执行的结果可能是不可预测的。
Deduplication batch command request parameters.
在某些情况下,您的批处理方法可能取决于在请求中跳过重复的第三方服务或库的行为。 它可以是一个休息服务,它期望唯一的值,并忽略重复。 在这种情况下,请求集合中的元素的大小可以不同于响应集合中的元素的大小。 它违反了行为原则之一。 要修复它,您需要手动将请求映射到响应,例如:
batchMethod( ids){ users restClientgetUsersByIds(ids); response ids stream() map(it users stream() .filter(u ugetId()equals(it)) findFirst()get()) .collect(toList()); response;
同样的情况,如果您想在服务调用之前从请求集合中删除重复的元素,则也要处理一下,例:
batchMethod( ids){ uniqueIds ids stream() distinct() collect(toList()); users restClientgetUsersByIds(uniqueIds); response ids stream() map(it usersstream() .filter(u ugetId()equals(it))findFirst()get()) .collect(toList()); response;
要设置collapser属性,请使用@ HystrixCollapser#collapserProperties
Collapser错误处理Bath命令可以有fallback方法。 例:
( ) getUserByIdWithFallback( id) { ; } ( ) getUserByIdsWithFallback( ids) { (); } getUserByIdsFallback( ids) { users (); ( id ids) { usersadd( (id, id)); } users; }
最后说一句,我们推荐你使用Javanica 1.4.+以上。
当然如果你使用spring cloud,那么这些全都为你做好了。
转载请注明:晓窗博客 » 微服务弹性框架hystrix-javanica详解(下)