本文主要研究一下spring cloud netflix的HystrixCommands。java
<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。react
spring-cloud-starter-netflix-hystrix-2.0.0.RELEASE.jar!/META-INF/maven/org.springframework.cloud/spring-cloud-starter-netflix-hystrix/pom.xmlgit
<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這個組件裏github
spring-cloud-netflix-core-2.0.0.RELEASE-sources.jar!/org/springframework/cloud/netflix/hystrix/HystrixCommands.javaweb
/** * 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而設計的。spring
@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()); }
另外配置文件也能夠指定默認的參數,好比apache
hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds : 6000 circuitBreaker: sleepWindowInMilliseconds: 10000 metrics: rollingStats: timeInMilliseconds : 18000
HystrixCommands就是spring cloud對netflix hystrix的包裝,以方便webflux裏頭使用hystrix,就免得再去使用AOP技術了。app