十次方后端笔记八:网关、配置中心和消息总线
搭建微服务网关以及使用 Spring Cloud ( Config + Bus ) 完成微服务配置中心

微服务网关

Spring Cloud技术栈采用Zuul作为微服务网关,在整个架构中,Zuul是所有其他微服务的统一入口,对所有请求进行路由。

管理后台微服务网关

后台网关微服务创建Module(省略)

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tensquare_parent</artifactId>
<groupId>com.tensquare</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tensquare_manager</artifactId>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>

</project>

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
server:
port: 9011
spring:
application:
name: tensquare‐manager #指定服务名
eureka:
instance:
prefer‐ip‐address: true
client:
service-url:
defaultZone: http://127.0.0.1:6868/eureka/
zuul:
routes:
tensquare‐gathering: #活动
path: /gathering/**
serviceId: tensquare‐gathering
tensquare‐article: #文章
path: /article/**
serviceId: tensquare‐article
tensquare‐base: #基础
path: /base/**
serviceId: tensquare‐base
tensquare‐friend: #交友
path: /friend/**
serviceId: tensquare‐friend
tensquare‐qa: #问答
path: /qa/**
serviceId: tensquare‐qa
tensquare‐recruit: #招聘
path: /recruit/**
serviceId: tensquare‐recruit
tensquare‐spit: #吐槽
path: /spit/**
serviceId: tensquare‐spit
tensquare‐user: #用户
path: /user/**
serviceId: tensquare‐user

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.tensquare.manager;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy
public class ManagerApplication {
public static void main(String[] args) {
SpringApplication.run(ManagerApplication.class, args);
}
}

前台微服务网关

前台网关微服务创建Module(省略)

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tensquare_parent</artifactId>
<groupId>com.tensquare</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tensquare_web</artifactId>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>

</project>

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
server:
port: 9012
spring:
application:
name: tensquare‐web #指定服务名
eureka:
instance:
prefer‐ip‐address: true
client:
service-url:
defaultZone: http://127.0.0.1:6868/eureka/
zuul:
routes:
tensquare‐gathering: #活动
path: /gathering/**
serviceId: tensquare‐gathering
tensquare‐article: #文章
path: /article/**
serviceId: tensquare‐article
tensquare‐base: #基础
path: /base/**
serviceId: tensquare‐base
tensquare‐friend: #交友
path: /friend/**
serviceId: tensquare‐friend
tensquare‐qa: #问答
path: /qa/**
serviceId: tensquare‐qa
tensquare‐recruit: #招聘
path: /recruit/**
serviceId: tensquare‐recruit
tensquare‐spit: #吐槽
path: /spit/**
serviceId: tensquare‐spit
tensquare‐user: #用户
path: /user/**
serviceId: tensquare‐user
tensquare‐search: #用户
path: /user/**
serviceId: tensquare‐search

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.tensquare.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}

前台网关转发Token

编写Zuul过滤器实现Token转发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.tensquare.web.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class WebFilter extends ZuulFilter {

@Override
public String filterType() {
return "pre";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() throws ZuulException {
System.out.println("zuul过滤器...");
//向header中添加鉴权令牌
RequestContext requestContext = RequestContext.getCurrentContext();
//获取header
HttpServletRequest request = requestContext.getRequest();
String authorization = request.getHeader("Authorization");
if (authorization != null) {
requestContext.addZuulRequestHeader("Authorization", authorization);
}
return null;
}
}

我的另一篇文章有详细介绍Zuul,文章链接:Zuul网关详解

后台网关转发Token

引入依赖

1
2
3
4
5
<dependency>
<groupId>com.tensquare</groupId>
<artifactId>tensquare_common</artifactId>
<version>${tensquare.version}</version>
</dependency>

配置Jwt相关常量

配置在application.yml即可

1
2
3
jwt:
config:
key: imxushuai

配置Bean

配置在ManagerApplication即可

1
2
3
4
@Bean
public JwtUtil jwtUtil(){
return new JwtUtil();
}

配置Zuul过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.tensquare.manager.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import util.JwtUtil;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@Component
public class ManagerFilter extends ZuulFilter {

@Autowired
private JwtUtil jwtUtil;

@Override
public String filterType() {
return "pre";
}

@Override
public int filterOrder() {
return 0;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
if (request.getMethod().equals("OPTIONS")) {// 跳过预请求
return null;
}
String url = request.getRequestURL().toString();
if (url.indexOf("/admin/login") > 0) {// 放行登录
log.info("登陆页面: [{}]", url);
return null;
}
String authHeader = request.getHeader("Authorization");//获取头信息
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
Claims claims = jwtUtil.parseJWT(token);
if (claims != null) {
if ("admin".equals(claims.get("roles"))) {
requestContext.addZuulRequestHeader("Authorization", authHeader);
log.info("Token验证通过,头信息 [{}]", authHeader);
return null;
}
}
}
requestContext.setSendZuulResponse(false);//终止运行
requestContext.setResponseStatusCode(401);//http状态码
requestContext.setResponseBody("无权访问");
requestContext.getResponse().setContentType("text/html;charset=UTF‐8");
return null;
}
}

配置中心

Spring Cloud Config

​ 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所 以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库 中。在spring cloud config组件中,分两个角色,一是config server,二是config client

  • Config Server是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git存储配置文件内容,也可以使用SVN存储,或者是本地文件存储。
  • Config Client是Config Server的客户端,用于操作存储在Config Server中的配置内容。微服务在启动时会请求Config Server获取配置文件的内容,请求到后再启动容器。

创建Git Repository(省略)

Git服务器上创建用于存放配置文件的仓库。创建好后,将所有的配置文件上传至Git服务器。

配置中心微服务

创建配置中心微服务Module(省略)

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>tensquare_parent</artifactId>
<groupId>com.tensquare</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tensquare_config</artifactId>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>

</project>

application.yml

1
2
3
4
5
6
7
8
9
10
spring:
application:
name: tensquare‐config
cloud:
config:
server:
git:
uri: https://github.com/imxushuai/tensquare_config.git
server:
port: 12000

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.tensquare.config;

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

@EnableConfigServer
@SpringBootApplication
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}

运行测试

成功拉取到配置文件!

Config Client配置

在需要从配置中心拉取配置的微服务中重复一下操作:

引入依赖

引入Spring Cloud Config依赖

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>

新增配置文件

resources目录中新增配置文件:bootstrap.yml

1
2
3
4
5
6
7
8
9
10
11
spring:
cloud:
config:
# 应用名
name: base
# 环境
profile: dev
# 分支
label: master
# 配置中心地址
uri: http://127.0.0.1:12000

配置完毕后,即可删除配置文件application.yml,测试是否能正常启动。

Spring Cloud Bus更新配置文件

使用Spring Cloud Bus实现实时更新配置文件,当Git库配置文件发送变动时,热更新相应微服务的配置文件。

原理参考:👉点击我👈

修改Config Server端

引入依赖

tensquare_config中引入依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>

application.yml新增配置

新增后的application.yml配置文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spring:
application:
name: tensquare‐config
cloud:
config:
server:
git:
uri: https://github.com/imxushuai/tensquare_config.git
rabbitmq:
host: 192.168.136.104
server:
port: 12000
management:
endpoints:
web:
exposure:
include: bus-refresh

修改Config Client端

在需要从配置中心拉取配置的微服务中重复一下操作:

引入依赖

引入Spring Cloud Bus依赖

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.yml新增配置

注意:这里新增的配置需要在Git服务器中的每个配置文件中加入下面这段配置。

1
2
3
spring:
rabbitmq:
host: 192.168.136.104

热更新配置文件说明

这样配置文件热更新的基本上算是完成了,以后在每一次配置文件有更新的时候,我们只需要调用一个接口,就可以完成配置文件的热更新了。

接口:POST http://127.0.0.1:12000/bus/refresh

需要直接调用的话,在spring cloud config server的配置文件中配置:management.security.enabled=false

一般的git库都会有web hook,当检测到提交时,会自动调用web hook设置的API地址,这样就可以完成自动热更新配置文件了。

更新私有配置项

Spring Cloud Bus更新只会更新框架已有的配置项,而不会更新类似Jwt等用户自定义的配置项。

需要更新自定义的配置项,需要在要更新配置项的Bean上使用@RefreshScope注解,这样就可以完成配置的更新。

文章作者: imxushuai
文章链接: https://www.imxushuai.com/2002/01/02/8.十次方后端笔记八:网关、配置中心和消息总线/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 imxushuai
支付宝打赏
微信打赏