springboot gateway网关+jwt+ribbon+zookeeper实现动态路由和负载均衡

springboot gateway网关+jwt+ribbon+zookeeper实现动态路由和负载均衡

  • 需求
  • 1. 什么是网关
  • 2. ribbon的作用
  • 3. 代码实现
    • 3.1 动态路由
    • 3.2 GatewayFilter过滤器实现

需求

    采用jwt的方式,前端携带token进行鉴权,后端采用微服务的方式提供服务,我们需要采用网关的方式对前端的访问进行限流、鉴权、负载均衡、监控、路由和灰度发布。 后端其他人员不再关注与权限与安全相关需求,只需要专注业务开发。

1. 什么是网关

    API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。

2. ribbon的作用

    因为gateway的特殊性LoadBalancerClientFilter过滤器主要解析lb:// 为前缀的路由规则,在通过LoadBalancerClient方法获取到需要的服务实例,从而实现负载均衡。在这里我们要写自己的负载均衡就需要重新需要重写LoadBalancerClientFilter 过滤器LoadBalancerClientFilter 介绍:次过滤器作用在url以lb开头的路由,然后利用loadBalancer来获取服务实例,构造目标requestUrl,设置到GATEWAYREQUESTURL_ATTR属性中,供NettyRoutingFilter使用。

    GatewayLoadBalancerClientAutoConfiguration 在初始化会检测@ConditionalOnBean(LoadBalancerClient.class) 是否存在,如果存在就会加载LoadBalancerClientFilter负载过滤器

3. 代码实现

代码实现github:
    网关中常用的Filter实现有两种方式,一种是GatewayFilter,实现该过滤器需要根据url来指定需要的过滤器,并且需要实现Ordered(数字小的优先);第二种是GlobalFilter,实现该过滤器则所有的请求都会经过该过滤器。

3.1 动态路由

    常规的路由的实现方式主要是在yml里面进行配置,这样的话需要每次都重启服务来配置路由,非常麻烦。因此通过某种方式实现动态修改路由就很重要。直接上代码:

    在springboot启动的时候就加载路由规则,同时在修改路由规则之后也会调用GatewayServiceHandler刷新一遍路由规则到内存中。

@Service
public class GatewayServiceHandler implements ApplicationEventPublisherAware, CommandLineRunner{
    private final static Logger log = LoggerFactory.getLogger(GatewayServiceHandler.class);

    @Autowired
    private RedisRouteDefinitionRepository routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
    // 获取数据dao
    @Autowired
    private GatewayRouteDefinitionMapper gatewayRouteMapper;
    // springboot启动后执行
    @Override
    public void run(String... args){
        this.loadRouteConfig();
    }
    /**
     * 更新路由
     * @return
     */
    public String loadRouteConfig() {
        //从数据库拿到路由配置
        List<GatewayRouteDefinition> gatewayRouteList = gatewayRouteMapper.queryAllRoutes();
        log.info("网关配置信息:=====>"+ JSON.toJSONString(gatewayRouteList));
        gatewayRouteList.forEach(gatewayRoute -> {
            //todo 增加断言/路由规则校验
            // 创建路由对象
            RouteDefinition definition = new RouteDefinition();
            definition.setId(gatewayRoute.getId());
            // 设置路由执行顺序
            definition.setOrder(gatewayRoute.getOrder());
            // 设置路由规则转发的目标uri
            URI uri = URI.create(gatewayRoute.getUri());
            definition.setUri(uri);
            // 设置路由断言
            String predicatesJson = gatewayRoute.getPredicatesJson();
            List<PredicateDefinition> predicates = new ArrayList<>();
            if (StringUtils.isNotBlank(predicatesJson)){
                List<GatewayPredicateDefinition> predicateDefinitions = JSONArray.parseArray(predicatesJson, GatewayPredicateDefinition.class);
                predicateDefinitions.stream().forEach(it->{
                    PredicateDefinition p = new PredicateDefinition();
                    p.setName(it.getName());
                    p.setArgs(it.getArgs());
                    predicates.add(p);
                });
            }
            definition.setPredicates(predicates);
            // 设置过滤器
            String filtersJson = gatewayRoute.getFiltersJson();
            List<FilterDefinition> filters = new ArrayList<>();
            if (StringUtils.isNotBlank(filtersJson)){
                List<GatewayFilterDefinition> filterDefinitions = JSONArray.parseArray(filtersJson, GatewayFilterDefinition.class);
                filterDefinitions.stream().forEach(it->{
                    FilterDefinition f = new FilterDefinition();
                    f.setName(it.getName());
                    f.setArgs(it.getArgs());
                    filters.add(f);
                });
            }
            definition.setFilters(filters);
            // 保存路由
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        });
        // 发送更新路由事件
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }

    /**
     * 删除路由
     * @param routeId
     */
    public void deleteRoute(String routeId){
        routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
        // 发送更新路由事件
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

上面代码是,下面是路由缓存机制

@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
//缓存的key
    public static final String GATEWAY_ROUTES = "gateway";
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        redisTemplate.opsForHash().values(GATEWAY_ROUTES).stream().forEach(routeDefinition -> {
            routeDefinitions.add(JSON.parseObject(routeDefinition.toString(), RouteDefinition.class));
        });
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route
                .flatMap(routeDefinition -> {
                    redisTemplate.opsForHash().put(GATEWAY_ROUTES, routeDefinition.getId(),
                            JSON.toJSONString(routeDefinition));
                    return Mono.empty();
                });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            if (redisTemplate.opsForHash().hasKey(GATEWAY_ROUTES, id)) {
                redisTemplate.opsForHash().delete(GATEWAY_ROUTES, id);
                return Mono.empty();
            }
            return Mono.defer(() -> Mono.error(new NotFoundException("路由文件没有找到: " + routeId)));
        });
    }
}

3.2 GatewayFilter过滤器实现

@Component
public class LogFilter implements GatewayFilter, Ordered {

   static final Logger logger = LogManager.getLogger("request");
   @Override
   public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
       log.info("=================进入自定义全局过滤器=============");
       StringBuilder logBuilder = new StringBuilder();
       ServerHttpRequest serverHttpRequest = exchange.getRequest();
       String method = serverHttpRequest.getMethodValue().toUpperCase();
       logBuilder.append(method).append(",").append(serverHttpRequest.getURI());
       if("POST".equals(method)) {
           String body = exchange.getAttributeOrDefault("cachedRequestBody", "");
           if(StringUtils.isNotBlank(body)) {
               logBuilder.append(",body=").append(body);
           }
       }

       ServerHttpResponse serverHttpResponse = exchange.getResponse();
       DataBufferFactory bufferFactory = serverHttpResponse.bufferFactory();
       ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(serverHttpResponse) {
           @Override
           public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
               if (body instanceof Flux) {
                   Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                   return super.writeWith(fluxBody.map(dataBuffer -> {
                       byte[] content = new byte[dataBuffer.readableByteCount()];
                       dataBuffer.read(content);
                       DataBufferUtils.release(dataBuffer);
                       String resp = new String(content, Charset.forName("UTF-8"));
                       logBuilder.append(",resp=").append(resp);
                       logger.info(logBuilder.toString());
                       byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();
                       return bufferFactory.wrap(uppedContent);
                   }));
               }
               return super.writeWith(body);
           }
       };
       return chain.filter(exchange.mutate().response(decoratedResponse).build());
   }

       @Override
       public int getOrder() {
           return -20;
       }
   }

注意:

过滤器的核心是实现AbstractGatewayFilterFactory,例如下面的LogGatewayFilterFactory在加入到gateway的filterfactory(系统默认的会实现19种内置过滤方式)的代码中的时候会把“Log”截取下来,当做filter的名称,只有这样才能配置的时候获取到这个过滤器。

@Component
public class LogGatewayFilterFactory  extends AbstractGatewayFilterFactory<Object> {
    @Override
    public GatewayFilter apply(Object config) {
        return new LogFilter();
    }
}

你可能感兴趣的:(网关,过滤器,java)