前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[spring guides]网关入门

[spring guides]网关入门

作者头像
_淡定_
发布2020-10-29 11:14:00
7000
发布2020-10-29 11:14:00
举报
文章被收录于专栏:dotnet & java

原文

目的

构建一个spring cloud的网关

实现

简单demo

使用Hystrix

springcloud-hystrix

简介

它是Netflix公司出的,2018年11月17发布了最后一个版本后,就转到了维护阶段,因为功能上已经满足他们的需求。现在他们内部新的系统使用resilience4j来实现Hystrix的功能。

分布式系统中,服务之间存在非常多的相互依赖,当某个依赖项出现不可用的情况(这个是无法避免的)的时候,Hystrix会提供一个fallback的方法,快速返回结果(虽然是错误的),来避免错误整个系统出现一连串级联的调用报错之类的。

顺道提一下,他通过命令模式来实现,也就是说把具体方法的执行交给了命令实现对象。

一个简单demo
代码语言:javascript
复制
//首先通过继承HystrixCommand<String>来定义一个返回String的Command。
public class HelloFailureCommand extends HystrixCommand<String> {
    //一般给命令起个名字
    private String name;

    public HelloFailureCommand(String name) {
        super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
        this.name = name;
    }
    //正常情况下会执行run方法,这里模拟run方法出错。
    @Override
    protected String run() throws Exception {
        throw new RuntimeException("this command always fails");
    }
    //提供一个fallback,用于正常run方法出错的时候调用
    @Override
    protected String getFallback() {
        return "Hello Failure " + name + "!";
    }
}
代码语言:javascript
复制
@Test
public void testSynchronous() {
  	//调用execute来执行run
    assertEquals("Hello Failure World!", new HelloFailureCommand("World").execute());
    assertEquals("Hello Failure Bob!", new HelloFailureCommand("Bob").execute());
}

使用

我们来实现一个circuit breaker(断路器)来实现服务降级。当服务调用失败,返回一个自定义信息。

Maven依赖
代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

httpbin中有个delay(延迟)服务,地址http://httpbin.org/delay/3 表示延迟3秒后返回数据。springcloud-gateway默认的超时时间为1秒,可以通过hystrix.command.default.execution.isolation.thread.timeoutInMillseconds来设置。如下设置成4秒。

代码语言:javascript
复制
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 4000
route
代码语言:javascript
复制
@Bean
public RouteLocator myRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
            .route("hystrix-route", predicateSpec -> predicateSpec
                    .host("*.hystrix.com")//处理host=*.hystrix.com的请求。
                    .filters(gatewayFilterSpec -> gatewayFilterSpec
                            .hystrix(config -> {
                                        config
                                                .setName("mycmd")
                                                .setFallbackUri("forward:/fallback");//设置错误的之后的地址
                                    }
                            ))
                    .uri("http://httpbin.org"))
            .build();
}
测试
代码语言:javascript
复制
$ curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/4
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 8

fallback  

上面设置了delay为4秒,那么httpbin的请求时间就会超过4秒,就会触发hystrix的fallback,然后根据设置的fallbackUri,转发到/fallback地址去,返回fallback的内容。

代码语言:javascript
复制
$ curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/2
HTTP/1.1 200 OK
Date: Fri, 16 Oct 2020 06:33:25 GMT
Content-Type: application/json
Content-Length: 470
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Content-Length": "0",
    "Forwarded": "proto=http;host=www.hystrix.com;for=\"127.0.0.1:59041\"",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.64.1",
    "X-Amzn-Trace-Id": "Root=1-5f893eb3-40498f08215677a430065c80",
    "X-Forwarded-Host": "www.hystrix.com"
  },
  "origin": "127.0.0.1, x.x.x.x",
  "url": "http://www.hystrix.com/delay/2"
}

测试delay为2秒,httpbin在4秒内返回了数据,gateway就可以显示httpbin的返回。

测试

wiremock是个nb的东西。

添加maven依赖

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>spring-boot-starter-web</artifactId>
            <groupId>org.springframework.boot</groupId>
        </exclusion>
    </exclusions>
</dependency>
代码语言:javascript
复制
// 模拟返回的body
class TempBody {
    private HashMap<String, String> headers;

    public HashMap<String, String> getHeaders() {
        return headers;
    }
    public void setHeaders(HashMap<String, String> headers) {
        this.headers = headers;
    }
}
代码语言:javascript
复制
package com.lou.demo5;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.*;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        properties = {"httpbin=http://localhost:${wiremock.server.port}"})
@AutoConfigureWireMock(port = 0)//随机端口
class Demo5ApplicationTests {

    @Autowired
    private WebTestClient webTestClient;

    @Test
    void contextLoads() {
      	final TempBody getBody = new TempBody();
      	final HashMap<String, String> headers = new HashMap<>();
      	headers.put("Hello", "World");
    		getBody.setHeaders(headers);
      	//通过stub 来mock http服务
        stubFor(get(urlEqualTo("/get"))
                .willReturn(aResponse()
                        //设置返回的body
                        .withBody(JSON.toJSONString(getBody))
                        //设置类型
                        .withHeader("Content-Type", "application/json")//
                ));

        stubFor(get(urlEqualTo("/delay/3"))
                .willReturn(aResponse()
                        .withBody("fallback")
                        .withFixedDelay(3000))
        );

        webTestClient
                .get().uri("/get")
                .exchange()
                .expectStatus().isOk()
                .expectBody()
                .jsonPath("$.headers.Hello").isEqualTo("World");
        webTestClient
                .get().uri("/delay/3")
                .header("Host", "www.hystrix.com")
                .exchange()
                .expectStatus().isOk()
                .expectBody()
                .consumeWith(entityExchangeResult -> {
                    assertThat(entityExchangeResult.getResponseBody()).isEqualTo("fallback".getBytes());
                });
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-10-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目的
  • 实现
    • 简单demo
      • 使用Hystrix
        • 简介
        • 使用
    • 测试
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档