我是靠谱客的博主 哭泣康乃馨,最近开发中收集的这篇文章主要介绍Hystrix Javanica,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

hystrix-javanica

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

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

Maven样例:

<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>x.y.z</version>
</dependency>

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

<aspects>
...
<aspect name="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"/>
...
</aspects>

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

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

<aop:aspectj-autoproxy/>
<bean id="hystrixAspect" class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"></bean>

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

@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注解来注释方法:

public class UserService {
...
@HystrixCommand
public User getUserById(String id) {
return userResource.getUserById(id);
}
}
...

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


@HystrixCommand(groupKey="UserGroup", commandKey = "GetUserByIdCommand")
public User getUserById(String id) {
return userResource.getUserById(id);
}

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

异步执行

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


@HystrixCommand
public Future<User> getUserByIdAsync(final String id) {
return new AsyncResult<User>() {
@Override
public User invoke() {
return userResource.getUserById(id);
}
};
}

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

响应式执行

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


@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`来实现正常退化,像下面这样:

 @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注释对其进行注释,如下所示:


@HystrixCommand(fallbackMethod = "defaultUser")
public User getUserById(String id) {
return userResource.getUserById(id);
}
@HystrixCommand
private User defaultUser(String id) {
return new User();
}

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


@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中得到的。

示例:


@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


@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


@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


@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,这可能是很方便,
如果你看到这种情况是非常有帮助的,那么请来创建问题以便我们很好支持。


@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相同的原因,不支持这种情况。


@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功能有相同的限制。

类或具体命令的默认回退

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


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,不要重复你自己)并摆脱冗余:


@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具有指定应被忽略的异常类型的能力。


@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出现。


@HystrixCommand(
ignoreExceptions = {BadRequestException.class},
raiseHystrixExceptions = {HystrixException.RUNTIME_EXCEPTION})
public User getUserById(String id) {
return userResource.getUserById(id);
}

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


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’设置,如下所示:


@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500")
})
public User getUserById(String id) {
return userResource.getUserById(id);
}

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

ConfigurationManager.getConfigInstance().setProperty("hystrix.command.getUserById.execution.isolation.thread.timeoutInMilliseconds", "500");

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

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


@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参数来指定这些属性(覆盖默认行为)。例:


@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 Javanica所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部