• 基于spring-cloud的微服务(4)API网关zuul


    API网关是微服务架构中的很重要的一个部分,内部有多个不同的服务提供给外部来使用,API网关可以对外做统一的入口,也可以在网关上做协议转换,权限控制和请求统计和限流等其他的工作
    spring-cloud封装了Netflix提供的开源的API网关实现zuul,我们可以很方便地启动一个zuul网关的实例,并支持向eureka进行注册,并对在eureka上已经注册的服务进行代理

    使用IDEA的spring initializer来创建一个zuul项目

    填写相关的group类型等信息,选择使用gradle来进行构建

    选择zuul和eureka client

    选择项目位置和gradle安装的位置:

    在启动类上添加 @EnableZuulProxy 注解,这个注解是@EnableZuulServer的加强版,不仅标识了这是一个zuul Server 而且启用了eureka注册中心和负载均衡ribbon

    启动类的代码:

    package com.jiaoyiping.springcloud.zuul;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
    
    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
    
    	    public static void main(String[] args) {
    	    SpringApplication.run(ZuulApplication.class, args);
        }
    }
    

    zuul最本质的功能是做反向代理,路由转发和对请求的拦截和处理,路由转发的配置在配置文件中,zuul可以做一下几种形式的转发:

    将请求重定向到一个外部的URL上,
    如果我们要配置,符合/baidu前缀的请求都重定向到baidu.com去,可以做如下的配置:

    zuul:
      routes:
        baidu:
          path: /baidu/**
          url: http://www.baidu.com
    

    将请求转发到内部提供的请求路径上去,使用forforward:
    比如,如果我们的网关自己提供了一个以/session开头的服务,我们想让对网关的请求中以/session开头的请求都让网关自己提供的这个服务来处理,则可以进行如下的配置

    zuul:
      routes:
        session:
          path: /session/**
          url: forward:/session    
    

    对已经注册到eureka中的服务进行代理和请求转发,此时只需要提供eureka中服务的serviceid即可

     zuul:
       routes:
         provider:
           path: /provider/**
           serviceId: PROVIDER
           #(去请求目标服务的时候)是否丢掉前缀,根据需求来配置
           stripPrefix: true
    

    完整的配置如下:

    spring:
      application:
        name: zuul
      cloud:
        inetutils:
          preferred-networks: 192.168.1.
    server:
      port: 8084
      tomcat:
        uri-encoding: UTF-8
      servlet:
        context-path: /
    logging:
      config: classpath:logback.xml
    zuul:
      routes:
        baidu:
          path: /baidu/**
          url: http://www.baidu.com
        provider:
          path: /provider/**
          serviceId: PROVIDER
          #(去请求目标服务的时候)是否丢掉前缀,根据需求来配置
          stripPrefix: true
        session:
          path: /session/**
          url: forward:/session
    eureka:
      instance:
        hostname: 192.168.1.5
        prefer-ip-address: true
        instance-id: 192.168.1.5:${server.port}
      client:
        healthcheck:
          enabled: true
        registerWithEureka: true
        fetchRegistry: true
        service-url:
          defaultZone: http://127.0.0.1:8081/eureka/
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 25000
    
    ribbon:
      MaxAutoRetries: 2
      MaxAutoRetriesNextServer: 3
      restclient:
        enabled: true
    

    zuul中的Filter的配置,zuul中提供了三种类型的Filter,preFilter,routeFilter和postFilter,分别对应请求中的不同的阶段,针对同一个请求,有一个RequestContext对象,在三个阶段的Filter中进行共享

    假设我们要开发一个统计请求时间的功能,需要在preFilter里边记录开始时间,并将整个开始时间放在RequestContext中,在postFilter里边拿到开始时间,用当前的时间减去开始时间,就是请求执行的时间

    定义一个preFilter:

    package com.jiaoyiping.springcloud.zuul.filter;
    
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import com.netflix.zuul.exception.ZuulException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
    
    /**
     * Created with Intellij IDEA
     *
     * @author: jiaoyiping
     * Mail: jiaoyiping@gmail.com
     * Date: 2018/04/05
     * Time: 16:24
     * To change this template use File | Settings | Editor | File and Code Templates
     */
    
    public class TimeCostPreFilter extends ZuulFilter {
        public static final String START_TIME_KEY = "start_time";
        private Logger logger = LoggerFactory.getLogger(TimeCostPreFilter.class);
    
        @Override
        public String filterType() {
            return FilterConstants.PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return 0;
        }
    
        /**
         * 判断是否要拦截的逻辑
         *
         * @return
         */
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            long startTime = System.currentTimeMillis();
            RequestContext.getCurrentContext().set(START_TIME_KEY, startTime);
            return null;
        }
    }
    

    定义以postFilter:

    package com.jiaoyiping.springcloud.zuul.filter;
    
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import com.netflix.zuul.exception.ZuulException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
    
    /**
     * Created with Intellij IDEA
     *
     * @author: jiaoyiping
     * Mail: jiaoyiping@gmail.com
     * Date: 2018/04/05
     * Time: 16:37
     * To change this template use File | Settings | Editor | File and Code Templates
     */
    
    public class TimeCostPostFilter extends ZuulFilter {
        private static final String START_TIME_KE = "start_time";
        private Logger logger = LoggerFactory.getLogger(TimeCostPostFilter.class);
    
        @Override
        public String filterType() {
            return FilterConstants.POST_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return 0;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            long startTime = (long) RequestContext.getCurrentContext().get(START_TIME_KE);
            logger.info("请求完成,耗时{}秒", (System.currentTimeMillis() - startTime) / 1000);
            return null;
        }
    }
    

    在一个配置类中将这两个Filter注入:

    package com.jiaoyiping.springcloud.zuul.config;
    
    import com.jiaoyiping.springcloud.zuul.filter.PDSFilter;
    import com.jiaoyiping.springcloud.zuul.filter.TimeCostPostFilter;
    import com.jiaoyiping.springcloud.zuul.filter.TimeCostPreFilter;
    import com.netflix.zuul.ZuulFilter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * Created with Intellij IDEA
     *
     * @author: jiaoyiping
     * Mail: jiaoyiping@gmail.com
     * Date: 2018/04/05
     * Time: 17:32
     * To change this template use File | Settings | Editor | File and Code Templates
     */
    @Configuration
    public class FilterConfig {
    
        @Bean
        public ZuulFilter timeCostPreFilter() {
            return new TimeCostPreFilter();
        }
    
        @Bean
        public ZuulFilter timeCostPostFilter() {
            return new TimeCostPostFilter();
        }
    
    
        @Bean
        public ZuulFilter pdsFilter() {
            return new PDSFilter();
        }
    }
    

    启动项目,可以发现,zuul网关已经注册到了eureka上:

    请求provide对应的地址,发现,zuul可以成功地调用eureka上对应的服务,并将结果正确返回:

  • 相关阅读:
    java基础之多线程一:概述
    java基础之io流总结四:字符流读写
    java基础之io流总结三:字节流读写
    java基础之io流总结二:File类基本应用
    java基础之io流总结一:io流概述
    java基础之集合:List Set Map的概述以及使用场景
    java基础之集合长度可变的实现原理
    HDU 4770 Lights Against Dudely 暴力枚举+dfs
    HDU 4771 BFS + 状压
    Codeforces Round #269 (Div. 2) D
  • 原文地址:https://www.cnblogs.com/jiaoyiping/p/8727054.html
Copyright © 2020-2023  润新知