一,整体网关环境架构

网关gateway配合redis实现分布式的会话共享_eureka

    1,整体服务通过Eureka注册中心实现服务注册和发现

    2,两个Order项目用来演示网关默认内置的负载均衡

    3,Config Server服务用来获取分布式配置信息,实现网关服务配置信息的动态分离和变更

    4,Zuul服务为网关服务,实现网关化的服务调用和分布式配置信息读取

    5,Pay服务为后加服务,用来演示分布式配置信息后,服务的动态添加

二,注册中心环境搭建

    * maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>
  <!-- 管理依赖 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Finchley.M7</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <!--SpringCloud eureka-server -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
  </dependencies>
  <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/libs-milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

    1,启动类

package com.gupao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @author pj_zhang
 * @create 2019-01-30 19:30
 **/
@SpringBootApplication
@EnableEurekaServer
public class GatewayEurekaApp {

    public static void main(String[] args) {
        SpringApplication.run(GatewayEurekaApp.class, args);
    }

}

    2,配置文件 -- application.yml

server:
  port: 8000
spring:
  application:
    name: eureka-server

###eureka 基本信息配置
eureka:
  instance:
    ###注册到eureka ip地址
    hostname: 127.0.0.1
  client:
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    ###因为自己是为注册中心,不需要自己注册自己
    register-with-eureka: false
    ###因为自己是为注册中心,不需要检索服务
    fetch-registry: false

三,服务端环境搭建

    * maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>
  <!-- 管理依赖 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Finchley.M7</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <!-- SpringBoot整合eureka客户端 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>
  <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/libs-milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

    1,app-order

        * 搭建两个order服务,用于演示负载均衡

        * 启动类

package com.gupao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author pj_zhang
 * @create 2019-01-30 21:35
 **/
@SpringBootApplication
@EnableEurekaClient
public class SpringCloudGatewayZuulOrderApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayZuulOrderApp.class, args);
    }

}

        * Controller

package com.gupao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author pj_zhang
 * @create 2019-01-30 21:35
 **/
@SpringBootApplication
@EnableEurekaClient
public class SpringCloudGatewayZuulOrderApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayZuulOrderApp.class, args);
    }

}

        * 配置文件 -- application.yml

# 注册到euraka服务
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

server:
  port: 8200

spring:
  application:
    name: app-order

    2,app-member

        * 启动类

package com.gupao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author pj_zhang
 * @create 2019-01-30 21:40
 **/
@SpringBootApplication
@EnableEurekaClient
public class SpringCloudGatewayZuulMemberApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayZuulMemberApp.class, args);
    }

}

        * Controller

package com.gupao.springcloud.gateway.zuul.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author pj_zhang
 * @create 2019-01-30 21:41
 **/
@RestController
public class MemberController {

    @Value("${server.port}")
    private Integer port;

    @RequestMapping("/getMember")
    public String getMember(String token) {
        return "getMember, token = " + token + ", port = " + port;
    }

}

        * 配置文件 -- application.yml

# 注册到euraka服务
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

server:
  port: 8400

spring:
  application:
    name: app-member

    3,app-pay

        * 启动类

package com.gupao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author pj_zhang
 * @create 2019-01-30 23:19
 **/
@SpringBootApplication
@EnableEurekaClient
public class SpringCloudGatewayPayApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayPayApp.class, args);
    }

}

        * Controller

package com.gupao.springcloud.gateway.zuul.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author pj_zhang
 * @create 2019-01-30 21:37
 **/
@RestController
public class PayController {

    @Value("${server.port}")
    private Integer port;

    @RequestMapping("/getPay")
    public String getPay(String token) {
        return "getPay, token = " + token + ", port = " + port;
    }

}

        * 配置文件 -- application.yml

# 注册到euraka服务
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

server:
  port: 8700

spring:
  application:
    name: app-pay

四,Zuul网关实现服务调用(本地配置文件)

    * maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>
  <!-- 管理依赖 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Finchley.M7</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <!--SpringCloud gateway zuul网关 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
    <!-- SpringBoot整合eureka客户端 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>
  <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/libs-milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

    1,启动类

package com.gupao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;

/**
 * @author pj_zhang
 * @create 2019-01-30 21:26
 **/
@SpringBootApplication
@EnableEurekaClient
// 启动Zuul网关代理服务调用
@EnableZuulProxy
public class SpringCloudGatewayZuulApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayZuulApp.class, args);
    }

    /**
     * 动态读取Zuul配置信息
     * @return
     */
    @RefreshScope
    @ConfigurationProperties("zuul")
    public ZuulProperties zuulProperties() {
        return new ZuulProperties();
    }

}

    2,不带过滤参数实现服务调用

配置文件 -- application.yml

# 注册到euraka服务
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

server:
  port: 8100

# 配置下列信息后,前台路径调用带api-order、api-member参数时,会自动调用对应的服务ID
# 参数后路径则为服务的请求路径
zuul:
  routes:
    api-a:
      # 对路径进行拦截
      path: /api-order/**
      # 拦截路径只想的服务名称
      serviceId: app-order
    api-b:
      path: /api-member/**
      serviceId: app-member

        * 页面请求

网关gateway配合redis实现分布式的会话共享_zuul_02

网关gateway配合redis实现分布式的会话共享_SpringCloud_03

网关gateway配合redis实现分布式的会话共享_zuul_04

    3,带过滤参数实现服务调用,对token参数进行网关处理,不存在该参数的请求不允许到达服务端

        * Filter类

package com.gupao.springcloud.gateway.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author pj_zhang
 * @create 2019-01-30 21:56
 **/
@Component
public class TokenFilter extends ZuulFilter {

    /**
     * 过滤器类型
     * @return
     */
    @Override
    public String filterType() {
        // pre : 前置
        // post : 后置
        return "pre";
    }

    /**
     * 过滤器执行顺序
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否进行过滤
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 执行体
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        // 获取上下文对象
        RequestContext currentContext = RequestContext.getCurrentContext();
        // 获取request
        HttpServletRequest request = currentContext.getRequest();
        // 获取token参数
        String tokenValue = request.getParameter("token");
        if (StringUtils.isEmpty(tokenValue)) {
            // 表示不通过网关去执行请求, 返回给客户端
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody("zuul filter : token is null");
            currentContext.setResponseStatusCode(401);
            return null;
        }
        // 正常执行
        return null;
    }
}

        * 配置文件 -- 同上不变

        * 页面请求

             -- 带token参数,请求正常

网关gateway配合redis实现分布式的会话共享_zuul_05

            -- 不带token参数,请求被拦截掉

网关gateway配合redis实现分布式的会话共享_zuul_06

五,Zuul网关实现服务调用(分布式配置中心)

    1,在码云上创建仓库和文件,文件前缀与Config Client端服务名称对应,

网关gateway配合redis实现分布式的会话共享_eureka_07

    2,Config Server端环境搭建

        * maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>
  <!-- 管理依赖 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Finchley.M7</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <!--spring-cloud 整合 config-server -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    <!-- SpringBoot整合eureka客户端 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

  </dependencies>
  <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/libs-milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

        * 启动类

package com.gupao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author pj_zhang
 * @create 2019-01-30 22:13
 **/
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class SpringCloudGatewayConfigServerApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayConfigServerApp.class, args);
    }

}

        * 配置文件 -- application.yml

###服务注册到eureka地址
eureka:
  client:
    service-url:
           defaultZone: http://localhost:8000/eureka
spring:
  application:
    ####注册中心应用名称
    name: server-config
  cloud:
    config:
      server:
        git:
          ###git环境地址
          uri: https://gitee.com/zpj0427/spring-cloud-config.git
          ####搜索目录
          search-paths:
            - gateway
      ####读取分支
      label: master
####端口号
server:
  port: 8500

         * 页面查看文件,验证是否连接成功

网关gateway配合redis实现分布式的会话共享_网关_08

    3,Config Client端搭建,即Zuul服务改造

        * 添加maven依赖

<!-- acturator服务监控 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-config-client</artifactId>
    </dependency>

        * 配置文件修改 -- bootstrap.yml(此处注意文件名称必须修改,尝试过多种方式,发现还是需要修改)

            -- spring下application和cloud两个分支必须放在一起,如下,分开后启动报错

# 注册到euraka服务
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

server:
  port: 8100

### 启动actuator所有监控节点
management:
  endpoints:
    web:
      exposure:
        include: "*"

# 读取分布式配置信息
spring:
  application:
    name: gateway-zuul-server
  cloud:
    config:
    ####读取后缀
      profile: dev
      ####读取config-server注册地址
      discovery:
        service-id: server-config
        enabled: true

        * Controller -- 添加一个Controller类获取某一配置信息,验证获取分布式配置文件是否成功

package com.gupao.springcloud.gateway.zuul.filter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author pj_zhang
 * @create 2019-01-30 22:25
 **/
@RestController
@RefreshScope
public class ConfigController {

    @Value("${zuul.routes.api-a.path}")
    private String configValue;

    @RequestMapping("/getConfig")
    public String getConfig() {
        return configValue;
    }

}

        * 页面展示

             -- 获取配置信息

网关gateway配合redis实现分布式的会话共享_网关_09

             -- 页面请求

网关gateway配合redis实现分布式的会话共享_SpringCloud_10

六,基于分布式配置中心实现动态扩展

    1,在码云的配置文件上,再一个一个服务的网关路径,如下

网关gateway配合redis实现分布式的会话共享_eureka_11

    2,在Config Server端查看是否已经获取到

网关gateway配合redis实现分布式的会话共享_网关_12

    3,在客户端基于Actuator在Postman中进行手动配置信息刷新

        * 如下图,可以看到新加的配置信息被刷新到

网关gateway配合redis实现分布式的会话共享_zuul_13

    4,访问新增加的服务

网关gateway配合redis实现分布式的会话共享_gateway_14

七,Zuul + Nginx实现高可用集群

    * 搭建多台Zuul服务器

    * Nginx配置文件配置反向代理(具体反向代理配置方式参考Nginx文档

    * 客户端访问先访问到Nginx服务器,Nginx服务器负载均衡到后端某一台Zuul服务器,再通过Zuul服务网关处理后具体请求最终服务

    * 此处Nginx依旧是单点服务,可以通过Keepalived的VIP方式实现Nginx高可用

八,总结

    1,建议使用分布式配置中心进行服务配置,可实现服务的动态增删

bootstrap.yml

    3,之所以用码云,是因为github太TM慢了,扛不住了。。。墙啊墙啊。。。