Springboot 集成Springcloud gateway的入门

最近做项目使用到了springcloude gateway作为网关,因此在此记录下springcloud gateway的入门操作,后续再将源码解读写出来,先立个flag。

回归正题,Springcloud gateway是spring 最新推出的网关中间件,用于代替 Netflix Zuul,因为 Netflix Zuul是基于mvc实现的,并发性能较低,springcloud gateway底层是通过基于netty的webflux实现的,并发性能比较好,因为比较适合高并发的网关。

一、依赖配置(pom文件配置)

配置property和dependencyManagement(用于声明版本,给pom的子类直接引用

    <properties>
       <!-- <spring-cloud.version>Greenwich.SR2</spring-cloud.version>-->
        <spring-cloud.version>Hoxton.SR1</spring-cloud.version>
    </properties>
    
  <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.9.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

添加依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
		<dependency>
		            <groupId>org.springframework.cloud</groupId>
		            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		            <exclusions>
		                <exclusion>
		                    <groupId>com.google.guava</groupId>
		                    <artifactId>guava</artifactId>
		                </exclusion>
		            </exclusions>
		</dependency>

二、yml文件以及property文件的配置

1、bootstrap.yml文件(启动优先级最高)的配置

spring:
  application:
    #声明服务名称
    name: test-gateway-service
  cloud:
    gateway:
      discovery:
        locator:
          #这里配置声明是否使用springcloud gateway的服务注册,false 代表不使用
          enabled: false
      default-filters:
        #声明默认的filter为Hystrix
        - name: Hystrix
          args:
            name : default
            #声明默认的回调接口
            fallbackUri: 'forward:/defaultFallback'
      #这里配置路由规则,可以通过配置文件配置,也可以通过写代码配置,
      #这里只展示通过配置文件配置的方式,往后展示通过代码配置的方式
      routes:
        - id: test1-inside-router
          #这里指定命中path中的路径的请求会跳转到test1-service的微服务中
          uri: lb://test1-service
          predicates:
            - Path=/justTest/**
          filters:
            - StripPrefix=1
        - id: test2-inside-router
        -  #这里指定命中path中的路径的请求会跳转到test2-service的微服务中
          uri: lb://test2-service
          predicates:
            - Path=/test/shop/**
          filters:


#这里单独声明hystrix熔断服务配置
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE
          thread:
            timeoutInMilliseconds: 4000

至此,springboot集成springcloud gateway即完成

对于路由规则的配置,除了可以通过yml或者property文件配置之外,还可以通过代码的形式,代码的形式样例代码如下:

@Configuration
@Log4j2
public class FilterConfigration {
    
    


    @Bean
    public RouteLocator testOutSideRoute(RouteLocatorBuilder builder) {
    
    

        return builder.routes()
                .route(r ->
                        r.path("/justTest/**")
                                .filters(
                                        f -> f.filters(new CommonAuthFilter())
                                )
                                .uri("lb://test1-service")
                )
                .build();
    }

    @Bean
    public RouteLocator shopOutSideRoute(RouteLocatorBuilder builder) {
    
    
        return builder.routes()
                .route(r ->
                        r.path("test/shop/**")
                                .filters(
                                        f -> f.filters(new CommonAuthFilter())
                                )
                                .uri("lb://test2-service")
                )
                .build();
    }
}

至此,网关已经可以跑起来,并路由到相应的接口,但是,网关的作用并不是仅限于此,还可以做鉴权、给修改、增加请求的参数等等(暂时先不说限流、熔断的功能,后续会详聊),如果想拦截请求,并做相应的修改或者做日志记录等,springcloud gateway给我们开了口子,可以通过定义全局的filter或者自定义的filter来实现。

这里仅仅展示做简单的认证并记录请求的全局filter。


import com.alibaba.fastjson.JSON;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@Log4j2
public class AuthAndLogFilter implements GlobalFilter, Ordered {
    
    

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    

        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        ServerHttpResponse serverHttpResponse = exchange.getResponse();
  
        log.info("==========网关收到请求:{}==========", serverHttpRequest.getPath());
        StringBuilder logBuilder = new StringBuilder();
        List<String> tokenList = serverHttpRequest.getHeaders().get("token");
        Map<String, Object> mapResult = new HashMap<>();
        String requestUrl = exchange.getRequest().getPath().toString();

        if (requestUrl.startsWith("/test/a/b/")
        ) {
    
    
            log.info("白名单路径,无需校验token");
        } else {
    
    
            if (!CollectionUtils.isEmpty(tokenList)) {
    
    
                String token = tokenList.get(0);
                log.info("上送的token为:{}" , token);
                if (!redisTemplate.hasKey(token)) {
    
    
                    log.info("登录超时,需要重新登录");
                    mapResult.put("code", 500);
                    mapResult.put("message", "登录超时,请重新登录");
                    DataBuffer bodyDataBuffer = serverHttpResponse.bufferFactory().wrap(JSON.toJSONString(mapResult).getBytes());
                    serverHttpResponse.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
                    return serverHttpResponse.writeWith(Mono.just(bodyDataBuffer));
                }
            } else {
    
    
                log.info("没有上送token");
                mapResult.put("code", 500);
                mapResult.put("message", "登录超时,请重新登录");
                DataBuffer bodyDataBuffer = serverHttpResponse.bufferFactory().wrap(JSON.toJSONString(mapResult).getBytes());
                serverHttpResponse.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
                return serverHttpResponse.writeWith(Mono.just(bodyDataBuffer));
            }
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
    
    
     /**
	 * Get the order value of this object.
	 * Higher values are interpreted as lower priority. As a consequence,
	 * the object with the lowest value has the highest priority (somewhat
	 * analogous to Servlet {@code load-on-startup} values).
	 * Same order values will result in arbitrary sort positions for the
	 * affected objects.
	 * 这个值越大,优先级越低,也就是加载的顺序越往后
	 */
        return -20;
    }
}

到这里,gateway网关可以跑起来了,但是如果放到生产环境还元不行,主要是有两个地方需要改进:

1)、路由规则都是写死的,万一又接口改动或者新增或者删除,则需要停服,重新发布才能生效。

2)、这里没有使用服务发现中间件,不适合微服务环境

针对问题1,可以使用基于分布式配置平台,将路由规则配置到分布式配置中间件,要改路由规则,只需要修改分布式配置文件即可,无需重启服务,或者通过开发api接口,实现代码层级自动化动态修改路由规则。

针对问题2,可以使用springcloud gateway + nacos的组合来实现服务发现和分布式配置。

以上两点,下一篇文章再做详细在展开。

猜你喜欢

转载自blog.csdn.net/weixin_46589575/article/details/113614916