一,整体网关环境架构
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
* 页面请求
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参数,请求正常
-- 不带token参数,请求被拦截掉
五,Zuul网关实现服务调用(分布式配置中心)
1,在码云上创建仓库和文件,文件前缀与Config Client端服务名称对应,
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
* 页面查看文件,验证是否连接成功
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;
}
}
* 页面展示
-- 获取配置信息
-- 页面请求
六,基于分布式配置中心实现动态扩展
1,在码云的配置文件上,再一个一个服务的网关路径,如下
2,在Config Server端查看是否已经获取到
3,在客户端基于Actuator在Postman中进行手动配置信息刷新
* 如下图,可以看到新加的配置信息被刷新到
4,访问新增加的服务
七,Zuul + Nginx实现高可用集群
* 搭建多台Zuul服务器
* Nginx配置文件配置反向代理(具体反向代理配置方式参考Nginx文档)
* 客户端访问先访问到Nginx服务器,Nginx服务器负载均衡到后端某一台Zuul服务器,再通过Zuul服务网关处理后具体请求最终服务
* 此处Nginx依旧是单点服务,可以通过Keepalived的VIP方式实现Nginx高可用
八,总结
1,建议使用分布式配置中心进行服务配置,可实现服务的动态增删
bootstrap.yml
3,之所以用码云,是因为github太TM慢了,扛不住了。。。墙啊墙啊。。。