序
本文主要研究一下spring cloud netflix的HystrixCommands。
maven
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
这个组件对hystrix进行了封装了,2.0.0.RELEASE全面支持了Reactor的Reactive Streams。
spring-cloud-starter-netflix-hystrix/pom.xml
spring-cloud-starter-netflix-hystrix-2.0.0.RELEASE.jar!/META-INF/maven/org.springframework.cloud/spring-cloud-starter-netflix-hystrix/pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<name>Spring Cloud Starter Netflix Hystrix</name>
<description>Spring Cloud Starter Netflix Hystrix</description>
<url>https://projects.spring.io/spring-cloud</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>https://www.spring.io</url>
</organization>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-serialization</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-metrics-event-stream</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
</dependency>
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava-reactive-streams</artifactId>
</dependency>
</dependencies>
</project>
这里要讲的HystrixCommands在spring-cloud-netflix-core这个组件里
HystrixCommands
spring-cloud-netflix-core-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/hystrix/HystrixCommands.java
/**
* Utility class to wrap a {@see Publisher} in a {@see HystrixObservableCommand}. Good for
* use in a Spring WebFlux application. Allows more flexibility than the @HystrixCommand
* annotation.
* @author Spencer Gibb
*/
public class HystrixCommands {
public static <T> PublisherBuilder<T> from(Publisher<T> publisher) {
return new PublisherBuilder<>(publisher);
}
public static class PublisherBuilder<T> {
private final Publisher<T> publisher;
private String commandName;
private String groupName;
private Publisher<T> fallback;
private Setter setter;
private HystrixCommandProperties.Setter commandProperties;
private boolean eager = false;
private Function<HystrixObservableCommand<T>, Observable<T>> toObservable;
public PublisherBuilder(Publisher<T> publisher) {
this.publisher = publisher;
}
public PublisherBuilder<T> commandName(String commandName) {
this.commandName = commandName;
return this;
}
public PublisherBuilder<T> groupName(String groupName) {
this.groupName = groupName;
return this;
}
public PublisherBuilder<T> fallback(Publisher<T> fallback) {
this.fallback = fallback;
return this;
}
public PublisherBuilder<T> setter(Setter setter) {
this.setter = setter;
return this;
}
public PublisherBuilder<T> commandProperties(
HystrixCommandProperties.Setter commandProperties) {
this.commandProperties = commandProperties;
return this;
}
public PublisherBuilder<T> commandProperties(
Function<HystrixCommandProperties.Setter, HystrixCommandProperties.Setter> commandProperties) {
if (commandProperties == null) {
throw new IllegalArgumentException(
"commandProperties must not both be null");
}
return this.commandProperties(
commandProperties.apply(HystrixCommandProperties.Setter()));
}
public PublisherBuilder<T> eager() {
this.eager = true;
return this;
}
public PublisherBuilder<T> toObservable(Function<HystrixObservableCommand<T>, Observable<T>> toObservable) {
this.toObservable = toObservable;
return this;
}
public Publisher<T> build() {
if (!StringUtils.hasText(commandName) && setter == null) {
throw new IllegalStateException("commandName and setter can not both be empty");
}
Setter setterToUse = getSetter();
PublisherHystrixCommand<T> command = new PublisherHystrixCommand<>(setterToUse, this.publisher, this.fallback);
Observable<T> observable = getObservableFunction().apply(command);
return RxReactiveStreams.toPublisher(observable);
}
public Function<HystrixObservableCommand<T>, Observable<T>> getObservableFunction() {
Function<HystrixObservableCommand<T>, Observable<T>> observableFunc;
if (this.toObservable != null) {
observableFunc = this.toObservable;
} else if (this.eager) {
observableFunc = cmd -> cmd.observe();
} else { // apply a default onBackpressureBuffer if not eager
observableFunc = cmd -> cmd.toObservable().onBackpressureBuffer();
}
return observableFunc;
}
public Setter getSetter() {
Setter setterToUse;
if (this.setter != null) {
setterToUse = this.setter;
} else {
String groupNameToUse;
if (StringUtils.hasText(this.groupName)) {
groupNameToUse = this.groupName;
} else {
groupNameToUse = commandName + "group";
}
HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(groupNameToUse);
HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(this.commandName);
HystrixCommandProperties.Setter commandProperties = this.commandProperties != null
? this.commandProperties
: HystrixCommandProperties.Setter();
setterToUse = Setter.withGroupKey(groupKey).andCommandKey(commandKey)
.andCommandPropertiesDefaults(commandProperties);
}
return setterToUse;
}
public Flux<T> toFlux() {
return Flux.from(build());
}
public Mono<T> toMono() {
return Mono.from(build());
}
}
private static class PublisherHystrixCommand<T> extends HystrixObservableCommand<T> {
private Publisher<T> publisher;
private Publisher<T> fallback;
protected PublisherHystrixCommand(Setter setter, Publisher<T> publisher,
Publisher<T> fallback) {
super(setter);
this.publisher = publisher;
this.fallback = fallback;
}
@Override
protected Observable<T> construct() {
return RxReactiveStreams.toObservable(publisher);
}
@Override
protected Observable<T> resumeWithFallback() {
if (this.fallback != null) {
return RxReactiveStreams.toObservable(this.fallback);
}
return super.resumeWithFallback();
}
}
}
从类注释可以看到这个类就是为了方便webflux应用使用hystrix而设计的。
实例
@Test
public void testHystrixFallback() throws InterruptedException {
Mono<String> delayMono = Mono.just("hello")
.delayElement(Duration.ofMillis(500));
Mono<String> result = HystrixCommands.from(delayMono)
.commandName("demoCmd")
.groupName("demoGroup")
.eager()
.commandProperties(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
.withExecutionTimeoutInMilliseconds(1000)
)
.fallback(Mono.just("from fallback"))
.toMono();
System.out.println(result.block());
}
- HystrixCommands.from方法可以对Publisher进行hystrix包装
- commandName用于指定hystrix的command名称
- groupName用于指定hystrix的group名称
- eager是默认方式,表示使用的是observe()方法,相当于hot Observable,只能消费从订阅时刻之后的数据,lazy使用的是toObservable()方法,相当于cold Observable,可以消费订阅之前的数据。
- commandProperties用于指定command的属性,比如executionIsolationStrategy、executionTimeoutInMilliseconds
- fallback用于指定fallback的操作
另外配置文件也可以指定默认的参数,比如
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds : 6000
circuitBreaker:
sleepWindowInMilliseconds: 10000
metrics:
rollingStats:
timeInMilliseconds : 18000
小结
HystrixCommands就是spring cloud对netflix hystrix的包装,以方便webflux里头使用hystrix,就省得再去使用AOP技术了。
doc
来源:oschina
链接:https://my.oschina.net/u/2922256/blog/1834363