我是靠谱客的博主 哭泣康乃馨,这篇文章主要介绍Hystrix Javanica,现在分享给大家,希望可以做个参考。

hystrix-javanica

Java语言比其他语言(如反射和注解)具有很大的优势。所有现代框架,如Spring,Hibernate,myBatis等都力求最大限度地利用这一优势。
在Hystrix中引入注解的想法是改进的明显解决方案。目前使用Hystrix涉及编写大量代码,这是快速开发的障碍。您可能花费大量时间编写Hystrix命令。
通过引入支持注解,Javanica项目使Hystrix更容易使用。

首先,为了使用hystrix-javanica,您需要在项目中添加hystrix-javanica依赖关系。

Maven样例:

复制代码
1
2
3
4
5
<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-javanica</artifactId> <version>x.y.z</version> </dependency>

在项目中实现AOP功能可使用了AspectJ库。如果在您的项目中已经使用AspectJ,那么需要在aop.xml中添加hystrix切面,如下所示:

复制代码
1
2
3
4
5
<aspects> ... <aspect name="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"/> ... </aspects>

关于AspectJ配置的更多信息请读这里

如果在项目中使用Spring AOP,则需要使用Spring AOP命名空间添加特定配置,以使Spring能够管理使用AspectJ编写的切面,并将HystrixCommandAspect声明为Spring bean,如下所示:

复制代码
1
2
<aop:aspectj-autoproxy/> <bean id="hystrixAspect" class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"></bean>

或者如果您使用的是Spring java配置:

复制代码
1
2
3
4
5
6
7
@Configuration public class HystrixConfiguration { @Bean public HystrixCommandAspect hystrixAspect() { return new HystrixCommandAspect(); } }

在Spring中使用哪种方法来创建代理并不重要,javanica适用于JDK和CGLIB代理。如果您为aop使用另一个支持AspectJ的框架,并使用其他lib(例如Javassist)创建代理,
那么让我们知道您用于创建代理的lib,我们将在不久的将来尝试添加对该库的支持。

更多关于Spring AOP AspectJ知识请读这里

切面织入

Javanica支持两种编织模式:编译时和运行时。目前加载时织入没有经过测试,但它应该工作。

如何使用

Hystrix命令

同步执行

要以Hystrix命令同步运行方法,您需要使用@HystrixCommand注解来注释方法:

复制代码
1
2
3
4
5
6
7
8
public class UserService { ... @HystrixCommand public User getUserById(String id) { return userResource.getUserById(id); } } ...

在上面的例子中,getUserById方法将在新的Hystrix命令中同步处理。默认情况下,command key的名称是命令方法名称:getUserById
默认group key 名称是被注释方法的类名称:UserService。当然,您也可以使用@HystrixCommand的属性更改它:

复制代码
1
2
3
4
5
@HystrixCommand(groupKey="UserGroup", commandKey = "GetUserByIdCommand") public User getUserById(String id) { return userResource.getUserById(id); }

设置threadPoolKey可使用@HystrixCommand#threadPoolKey()

异步执行

要异步处理Hystrix命令,您应该在命令方法中返回AsyncResult的实例,如下所示:

复制代码
1
2
3
4
5
6
7
8
9
10
@HystrixCommand public Future<User> getUserByIdAsync(final String id) { return new AsyncResult<User>() { @Override public User invoke() { return userResource.getUserById(id); } }; }

命令方法的返回类型应为Future,表示应该以异步方式执行命令

响应式执行

要想“Reactive Execution”,您应该在命令方法中返回一个Observable的实例,如下例所示:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@HystrixCommand public Observable<User> getUserById(final String id) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscriber<? super User> observer) { try { if (!observer.isUnsubscribed()) { observer.onNext(new User(id, name + id)); observer.onCompleted(); } } catch (Exception e) { observer.onError(e); } } }); }

命令方法的返回类型应该是Observable

HystrixObservable接口提供了两种方法:observe() - 与HystrixCommand#queue()HystrixCommand#execute()行为一样,立即开始执行命令;
toObservable() - 一旦Observable被订阅,懒惰地开始执行命令。
为了控制这种行为,并且在两种模式之间切换,@HystrixCommand提供了名为observableExecutionMode的特定属性。
@HystrixCommand(observableExecutionMode = EAGER)表示应该使用observe()方法执行observable命令;
@HystrixCommand(observableExecutionMode = LAZY)表示应该使用toObservable()方法来执行observable命令。

注意:默认情况下使用EAGER模式

Fallback

可以通过在@HystrixCommand中声明`fallbackMethod`来实现正常退化,像下面这样:

复制代码
1
2
3
4
5
6
7
@HystrixCommand(fallbackMethod = "defaultUser") public User getUserById(String id) { return userResource.getUserById(id); } private User defaultUser(String id) { return new User("def", "def"); }

重要的是要记住,Hystrix命令和回退方法应该放在同一个类中并具有相同的方法签名(执行失败的异常(诱发服务降级的异常)为可选参数)。回退方法可以有任何访问修饰符。

方法defaultUser将用于在任何错误的情况下处理回退逻辑。如果您需要将fallback methoddefaultUser作为单独的Hystrix命令运行,那么您需要使用HystrixCommand注释对其进行注释,如下所示:

复制代码
1
2
3
4
5
6
7
8
9
@HystrixCommand(fallbackMethod = "defaultUser") public User getUserById(String id) { return userResource.getUserById(id); } @HystrixCommand private User defaultUser(String id) { return new User(); }

如果回退方法标记为@HystrixCommand,那么这种回退方法(defaultUser)也可以有自己的回退方法,如下例所示:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
@HystrixCommand(fallbackMethod = "defaultUser") public User getUserById(String id) { return userResource.getUserById(id); } @HystrixCommand(fallbackMethod = "defaultUserSecond") private User defaultUser(String id) { return new User(); } @HystrixCommand private User defaultUserSecond(String id) { return new User("def", "def"); }

Javanica提供了在执行fallback中获取执行异常(导致命令失败抛出的异常)的能力。你可以使用附加参数扩展fallback方法签名,以获取命令抛出的异常。
Javanica通过fallback方法的附加参数来公开执行异常。执行异常是通过调用方法getExecutionException()在vanilla hystrix中得到的。

示例:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@HystrixCommand(fallbackMethod = "fallback1") User getUserById(String id) { throw new RuntimeException("getUserById command failed"); } @HystrixCommand(fallbackMethod = "fallback2") User fallback1(String id, Throwable e) { assert "getUserById command failed".equals(e.getMessage()); throw new RuntimeException("fallback1 failed"); } @HystrixCommand(fallbackMethod = "fallback3") User fallback2(String id) { throw new RuntimeException("fallback2 failed"); } @HystrixCommand(fallbackMethod = "staticFallback") User fallback3(String id, Throwable e) { assert "fallback2 failed".equals(e.getMessage()); throw new RuntimeException("fallback3 failed"); } User staticFallback(String id, Throwable e) { assert "fallback3 failed".equals(e.getMessage()); return new User("def", "def"); } // test @Test public void test() { assertEquals("def", getUserById("1").getName()); }

如你所见,附加的Throwable参数不是强制性的,可以省略或指定。fallback可以得到父层方法执行失败的异常,因此fallback3会收到fallback2抛出的异常,而不是getUserById命令中的异常。

Async/Sync fallback

回退可以是异步或同步,在某些情况下,它取决于命令执行类型,下面列出了所有可能的使用:

支持

case 1: 同步 command, 同步 fallback

复制代码
1
2
3
4
5
6
7
8
9
@HystrixCommand(fallbackMethod = "fallback") User getUserById(String id) { throw new RuntimeException("getUserById command failed"); } @HystrixCommand User fallback(String id) { return new User("def", "def"); }

case 2: 异步 command, 同步 fallback

复制代码
1
2
3
4
5
6
7
8
9
@HystrixCommand(fallbackMethod = "fallback") Future<User> getUserById(String id) { throw new RuntimeException("getUserById command failed"); } @HystrixCommand User fallback(String id) { return new User("def", "def"); }

case 3: 异步 command, 异步 fallback

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@HystrixCommand(fallbackMethod = "fallbackAsync") Future<User> getUserById(String id) { throw new RuntimeException("getUserById command failed"); } @HystrixCommand Future<User> fallbackAsync(String id) { return new AsyncResult<User>() { @Override public User invoke() { return new User("def", "def"); } }; }

不支持(禁止)

case 1: 同步 command, 异步 fallback。这种情况是不支持的,因为在本质上,一个调用者执行getUserById方法不会得到Future的结果,并且fallback方法提供的Future结果对调用者根本不可用。
因此执行命令会在调用者获得结果之前强制完成fallbackAsync,已经说过,事实证明,async fallback执行没有任何好处。但是,如果同步和异步命令同时使用某个fallback,这可能是很方便,
如果你看到这种情况是非常有帮助的,那么请来创建问题以便我们很好支持。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@HystrixCommand(fallbackMethod = "fallbackAsync") User getUserById(String id) { throw new RuntimeException("getUserById command failed"); } @HystrixCommand Future<User> fallbackAsync(String id) { return new AsyncResult<User>() { @Override public User invoke() { return new User("def", "def"); // 实际期望获取这个结果,但是被强制执行返回了Future<User>结果,该结果对调用者不可用 } }; }

case 2: 同步 command, 异步 fallback, 与案例1相同的原因,不支持这种情况。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
@HystrixCommand(fallbackMethod = "fallbackAsync") User getUserById(String id) { throw new RuntimeException("getUserById command failed"); } Future<User> fallbackAsync(String id) { return new AsyncResult<User>() { @Override public User invoke() { return new User("def", "def"); } }; }

在javanica中使用observable功能有相同的限制。

类或具体命令的默认回退

此功能允许为整个类或具体命令定义默认回退。如果您有一批具有完全相同的回退逻辑的命令,您仍然必须为每个命令定义回退方法,因为回退方法应该具有与命令完全相同的签名,请考虑以下代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Service { @RequestMapping(value = "/test1") @HystrixCommand(fallbackMethod = "fallback") public APIResponse test1(String param1) { // some codes here return APIResponse.success("success"); } @RequestMapping(value = "/test2") @HystrixCommand(fallbackMethod = "fallback") public APIResponse test2() { // some codes here return APIResponse.success("success"); } @RequestMapping(value = "/test3") @HystrixCommand(fallbackMethod = "fallback") public APIResponse test3(ObjectRequest obj) { // some codes here return APIResponse.success("success"); } private APIResponse fallback(String param1) { return APIResponse.failed("Server is busy"); } private APIResponse fallback() { return APIResponse.failed("Server is busy"); } private APIResponse fallback(ObjectRequest obj) { return APIResponse.failed("Server is busy"); } }

默认回退功能允许采用DRY原则(Don’t Repeat Yourself,不要重复你自己)并摆脱冗余:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@DefaultProperties(defaultFallback = "fallback") public class Service { @RequestMapping(value = "/test1") @HystrixCommand public APIResponse test1(String param1) { // some codes here return APIResponse.success("success"); } @RequestMapping(value = "/test2") @HystrixCommand public APIResponse test2() { // some codes here return APIResponse.success("success"); } @RequestMapping(value = "/test3") @HystrixCommand public APIResponse test3(ObjectRequest obj) { // some codes here return APIResponse.success("success"); } private APIResponse fallback() { return APIResponse.failed("Server is busy"); } }

默认的回退方法不应该有任何参数,除了可以附加获取执行异常参数,不应该抛出任何异常。以降序优先级列(如果设置1,则不执行2)出如下:

  1. 使用@HystrixCommand的fallbackMethod属性定义命令回退
  2. 使用@HystrixCommand的defaultFallback属性定义命令默认回退
  3. 使用@DefaultProperties的defaultFallback属性定义类默认回退

错误传播

基于此描述,@HystrixCommand具有指定应被忽略的异常类型的能力。

复制代码
1
2
3
4
5
@HystrixCommand(ignoreExceptions = {BadRequestException.class}) public User getUserById(String id) { return userResource.getUserById(id); }

如果userResource.getUserById(id);抛出类型为BadRequestException的异常,则此异常将被包装在HystrixBadRequestException中,并重新抛出,而不触发后备逻辑。
你不需要手动执行,javanica会为你做这个。

值得注意的是,默认情况下,一个调用者总是会得到根本原因异常,例如BadRequestException,而不是HystrixBadRequestExceptionHystrixRuntimeException(除非有执行代码显式抛出这些异常的情况)。

可选地,通过使用raiseHystrixExceptions,可以禁用HystrixRuntimeException的拆箱。即所有未被忽略的异常会作为HystrixRuntimeException的cause出现。

复制代码
1
2
3
4
5
6
7
@HystrixCommand( ignoreExceptions = {BadRequestException.class}, raiseHystrixExceptions = {HystrixException.RUNTIME_EXCEPTION}) public User getUserById(String id) { return userResource.getUserById(id); }

注意:如果命令有一个回退,则只有触发回退逻辑的第一个异常将被传播给调用者。例:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Service { @HystrixCommand(fallbackMethod = "fallback") Object command(Object o) throws CommandException { throw new CommandException(); } @HystrixCommand Object fallback(Object o) throws FallbackException { throw new FallbackException(); } } // in client code { try { service.command(null); } catch (Exception e) { assert CommandException.class.equals(e.getClass()) } }

请求缓存

……

配置

命令属性

命令属性可以使用@HystrixCommand的’commandProperties’设置,如下所示:

复制代码
1
2
3
4
5
6
7
@HystrixCommand(commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500") }) public User getUserById(String id) { return userResource.getUserById(id); }

Javanica使用Hystrix ConfigurationManager动态设置属性。对于上面的例子,Javanica幕后执行的动作:

复制代码
1
ConfigurationManager.getConfigInstance().setProperty("hystrix.command.getUserById.execution.isolation.thread.timeoutInMilliseconds", "500");

更多关于Hystrix命令属性command和fallback

ThreadPoolProperties可以使用@HystrixCommand的’threadPoolProperties’设置,如下所示:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@HystrixCommand(commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500") }, 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 User getUserById(String id) { return userResource.getUserById(id); }

默认属性

@DefaultProperties是类(类型)级别注释,允许设置的默认命令属性,有groupKeythreadPoolKeycommandPropertiesthreadPoolProperties
ignoreExceptionsraiseHystrixExceptions
默认情况下,使用此注释指定的属性将在注释类中定义的每个hystrix命令使用,除非命令明确使用相应的@HystrixCommand参数来指定这些属性(覆盖默认行为)。例:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
@DefaultProperties(groupKey = "DefaultGroupKey") class Service { @HystrixCommand // hystrix command group key is 'DefaultGroupKey' public Object commandInheritsDefaultProperties() { return null; } @HystrixCommand(groupKey = "SpecificGroupKey") // command overrides default group key public Object commandOverridesGroupKey() { return null; } }

Hystrix collapser

……

原文链接: hystrix-javanica & 推荐阅读

最后

以上就是哭泣康乃馨最近收集整理的关于Hystrix Javanica的全部内容,更多相关Hystrix内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部