搭建微服务网关以及使用 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过滤器..."); RequestContext requestContext = RequestContext.getCurrentContext(); 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); 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
注解,这样就可以完成配置的更新。