好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

spring cloud gateway集成hystrix实战篇

spring cloud gateway集成hystrix

本文主要研究一下spring cloud gateway如何集成hystrix

maven

?

1

2

3

4

< dependency >

             < groupId >org.springframework.cloud</ groupId >

             < artifactId >spring-cloud-starter-netflix-hystrix</ artifactId >

         </ dependency >

添加spring-cloud-starter-netflix-hystrix依赖,开启hystrix

配置实例

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

hystrix测试数据mand.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000

spring:

   cloud:

     gateway:

       discovery:

         locator:

           enabled: true

       routes:

       - id: employee-service

         uri: lb: //employee-service

         predicates:

         - Path=/employee/**

         filters:

         - RewritePath=/employee/(?<path>.*), /$\{path}

         - name: Hystrix

           args:

             name: fallbackcmd

             fallbackUri: forward:/fallback

首先filter里头配置了name为Hystrix的filter,实际是对应HystrixGatewayFilterFactory 然后指定了hystrix command的名称,及fallbackUri,注意fallbackUri要以forward开头 最后通过hystrix测试数据mand.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds指定该command的超时时间

fallback实例

?

1

2

3

4

5

6

7

8

@RestController

@RequestMapping ( "/fallback" )

public class FallbackController {

     @RequestMapping ( "" )

     public String fallback(){

         return "error" ;

     }

}

源码解析

GatewayAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@Configuration

@ConditionalOnProperty (name = "spring.cloud.gateway.enabled" , matchIfMissing = true )

@EnableConfigurationProperties

@AutoConfigureBefore (HttpHandlerAutoConfiguration. class )

@AutoConfigureAfter ({GatewayLoadBalancerClientAutoConfiguration. class , GatewayClassPathWarningAutoConfiguration. class })

@ConditionalOnClass (DispatcherHandler. class )

public class GatewayAutoConfiguration {

     //......

     @Configuration

     @ConditionalOnClass ({HystrixObservableCommand. class , RxReactiveStreams. class })

     protected static class HystrixConfiguration {

         @Bean

         public HystrixGatewayFilterFactory hystrixGatewayFilterFactory(DispatcherHandler dispatcherHandler) {

             return new HystrixGatewayFilterFactory(dispatcherHandler);

         }

     } 

     //......

}

引入spring-cloud-starter-netflix-hystrix类库,就有HystrixObservableCommand.class, RxReactiveStreams.class,便开启HystrixConfiguration

HystrixGatewayFilterFactory

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/HystrixGatewayFilterFactory.java

?

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

/**

  * Depends on `spring-cloud-starter-netflix-hystrix`, {@see http://cloud.spring.io/spring-cloud-netflix/}

  * @author Spencer Gibb

  */

public class HystrixGatewayFilterFactory extends AbstractGatewayFilterFactory<HystrixGatewayFilterFactory.Config> {

     public static final String FALLBACK_URI = "fallbackUri" ;

     private final DispatcherHandler dispatcherHandler;

     public HystrixGatewayFilterFactory(DispatcherHandler dispatcherHandler) {

         super (Config. class );

         this .dispatcherHandler = dispatcherHandler;

     }

     @Override

     public List<String> shortcutFieldOrder() {

         return Arrays.asList(NAME_KEY);

     }

     public GatewayFilter apply(String routeId, Consumer<Config> consumer) {

         Config config = newConfig();

         consumer.accept(config);

         if (StringUtils.isEmpty(config.getName()) && !StringUtils.isEmpty(routeId)) {

             config.setName(routeId);

         }

         return apply(config);

     }

     @Override

     public GatewayFilter apply(Config config) {

         //TODO: if no name is supplied, generate one from command id (useful for default filter)

         if (config.setter == null ) {

             Assert.notNull(config.name, "A name must be supplied for the Hystrix Command Key" );

             HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName());

             HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(config.name);

             config.setter = Setter.withGroupKey(groupKey)

                     .andCommandKey(commandKey);

         }

         return (exchange, chain) -> {

             RouteHystrixCommand command = new RouteHystrixCommand(config.setter, config.fallbackUri, exchange, chain);

             return Mono.create(s -> {

                 Subscription sub = command.toObservable().subscribe(s::success, s::error, s::success);

                 s.onCancel(sub::unsubscribe);

             }).onErrorResume((Function<Throwable, Mono<Void>>) throwable -> {

                 if (throwable instanceof HystrixRuntimeException) {

                     HystrixRuntimeException e = (HystrixRuntimeException) throwable;

                     if (e.getFailureType() == TIMEOUT) { //TODO: optionally set status

                         setResponseStatus(exchange, HttpStatus.GATEWAY_TIMEOUT);

                         return exchange.getResponse().setComplete();

                     }

                 }

                 return Mono.error(throwable);

             }).then();

         };

     }

     //......

}

这里创建了RouteHystrixCommand,将其转换为Mono,然后在onErrorResume的时候判断如果HystrixRuntimeException的failureType是FailureType.TIMEOUT类型的话,则返回GATEWAY_TIMEOUT(504, "Gateway Timeout")状态码。

RouteHystrixCommand

?

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

31

32

33

34

35

36

//TODO: replace with HystrixMonoCommand that we write

     private class RouteHystrixCommand extends HystrixObservableCommand<Void> {

         private final URI fallbackUri;

         private final ServerWebExchange exchange;

         private final GatewayFilterChain chain;

         RouteHystrixCommand(Setter setter, URI fallbackUri, ServerWebExchange exchange, GatewayFilterChain chain) {

             super (setter);

             this .fallbackUri = fallbackUri;

             this .exchange = exchange;

             this .chain = chain;

         }

         @Override

         protected Observable<Void> construct() {

             return RxReactiveStreams.toObservable( this .chain.filter(exchange));

         }

         @Override

         protected Observable<Void> resumeWithFallback() {

             if ( this .fallbackUri == null ) {

                 return super .resumeWithFallback();

             }

             //TODO: copied from RouteToRequestUrlFilter

             URI uri = exchange.getRequest().getURI();

             //TODO: assume always?

             boolean encoded = containsEncodedParts(uri);

             URI requestUrl = UriComponentsBuilder.fromUri(uri)

                     .host( null )

                     .port( null )

                     .uri( this .fallbackUri)

                     .build(encoded)

                     .toUri();

             exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);

             ServerHttpRequest request = this .exchange.getRequest().mutate().uri(requestUrl).build();

             ServerWebExchange mutated = exchange.mutate().request(request).build();

             return RxReactiveStreams.toObservable(HystrixGatewayFilterFactory. this .dispatcherHandler.handle(mutated));

         }

     }

这里重写了construct方法,RxReactiveStreams.toObservable(this.chain.filter(exchange)),将reactor的Mono转换为rxjava的Observable 这里重写了resumeWithFallback方法,针对有fallbackUri的情况,重新路由到fallbackUri的地址

Config

?

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

31

public static class Config {

         private String name;

         private Setter setter;

         private URI fallbackUri;

         public String getName() {

             return name;

         }

         public Config setName(String name) {

             this .name = name;

             return this ;

         }

         public Config setFallbackUri(String fallbackUri) {

             if (fallbackUri != null ) {

                 setFallbackUri(URI.create(fallbackUri));

             }

             return this ;

         }

         public URI getFallbackUri() {

             return fallbackUri;

         }

         public void setFallbackUri(URI fallbackUri) {

             if (fallbackUri != null && ! "forward" .equals(fallbackUri.getScheme())) {

                 throw new IllegalArgumentException( "Hystrix Filter currently only supports 'forward' URIs, found " + fallbackUri);

             }

             this .fallbackUri = fallbackUri;

         }

         public Config setSetter(Setter setter) {

             this .setter = setter;

             return this ;

         }

     }

可以看到Config校验了fallbackUri,如果不为null,则必须以forward开头

小结

spring cloud gateway集成hystrix,分为如下几步:

添加spring-cloud-starter-netflix-hystrix依赖 在对应route的filter添加name为Hystrix的filter,同时指定hystrix command的名称,及其fallbackUri(可选) 指定该hystrix command的超时时间等。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://HdhCmsTestjianshu测试数据/p/81b0059dbd98

查看更多关于spring cloud gateway集成hystrix实战篇的详细内容...

  阅读:18次