网关、配置管理(热更新)、动态路由 1.什么是网关 就是网络的关口,负责请求的路由、转发、身份校验 以前我们单体项目前端要向后端发起请求,很简单,直接发就行了 但是拆分成微服务之后就麻烦了:所以有了网关
就比如找人,你得有户口簿、打野才会给你开门,如果你不知道你要找的人在哪,大爷会带你去,这就叫做网关。 下面给你看更加专业的图 网关始终请求8080,这毋庸置疑,然后到了网关,他去判断前端请求的业务需要的是哪个微服务处理这个请求
那么这个判断的过程就是请求的路由
接下来网关就会将躯体的请求转发到具体的微服务了,这就是路由转发
当然了,部署上线 后的服务里面可能有多个实例,形成集群 ,所以要在多个实例之间运用负载均衡
所有的微服务信息就会服务注册 到注册中心 ,它里面就会有多有的微服务信息
当然网关也是一个微服务,启动之后也可以去注册中心拉取 所有的服务地址 由于前端只知道网关地址,因此整个微服务对前端来讲,是隐藏起来的黑盒,这样在前端看来现在的后端跟原来的单体架构没什么区别,这时候微服务就不用向外界暴露自己的端口地址了,也是对后端的一种保护。
2. 配置路由规则 1 2 3 4 5 6 7 8 9 10 11 12 spring: cloud: gateway: routes: - id: item uri: lb://item-service predicates: - Path=/items/** - id: xx uri: lb://xx-service predicates: - Path=/xx/**
3. 网关登录校验 执行顺序 网络请求JWT校验要在NettyRoutingFilter之前(PRE确保在路由转发之前进行校验)
自定义过滤器 GloablFilter 直接实现GloablFilter接口即可
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 @Component public class MyGlobalFilter implements GlobalFilter , Ordered { @Override public Mono<Void> filter (ServerWebExchange exchange, GatewayFilterChain chain) { HttpHeaders headers = exchange.getRequest().getHeaders(); System.out.println("headers = " + headers); return chain.filter(exchange); } @Override public int getOrder () { return Ordered.HIGHEST_PRECEDENCE; } }
[!NOTE] PS:从网关到微服务的用户传递 Spring Boot自动装配它不仅仅是面试的时候能用到,在实际的开发中也有着重要作用,就好比如,想让每个微服务都获取到用户信息,可以在Common下定义一个SpringMVC拦截器,要想使拦截器生效,需要配置spring.factories的扫描包,然后,最重要的是在配置类里面加上@ConditionalOnClass(DispatcherServlet.class)注解,这样才能实现拦截器。
4. 在微服务之间传递用户信息 OpenFeign传递用户
5.配置管理 共享配置
先在nacos添加配置
微服务拉去共享配置 具体流程图
1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-nacos-config</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-bootstrap</artifactId > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 spring: application: name: cart-service profiles: active: dev cloud: nacos: server-addr: 192.168 .150 .101 :8848 config: file-extension: yaml shared-configs: - dataId: shared-jdbc.yaml - dataId: shared-log.yaml - dataId: shared-swagger.yaml
配置热更新 当修改配置文件时,微服务无需重启 即可使配置生效。
前提条件:nacos中要有一个与微服务名有关的配置文件
1 2 3 4 [spring.application.name ]-[spring.active.profile]-[file-extension] // 微服务名称 项目profile(可选) 文件名后缀 // 例:user-service-dev-yaml
微服务中要以特定方式读取需要热更新的配置属性
1 2 3 4 5 6 7 8 9 import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;@Data @ConfigurationProperties(prefix = "hm.cart") public class CartProperties { private int maxItems; }
6.动态路由
监听Nacos配置变更的消息
当配置变更时,将最新的路由信息更新到网关路由表 以下是在网关微服务下配置动态路由的案例
JSON:
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 [ { "id" : "item" , "predicates" : [ { "name" : "Path" , "args" : { "_genkey_0" : "/items/**" , "_genkey_1" : "/search/**" } } ] , "filters" : [ ] , "uri" : "lb://item-service" } , { "id" : "cart" , "predicates" : [ { "name" : "Path" , "args" : { "_genkey_0" : "/carts/**" } } ] , "filters" : [ ] , "uri" : "lb://cart-service" } , { "id" : "user" , "predicates" : [ { "name" : "Path" , "args" : { "_genkey_0" : "/users/**" , "_genkey_1" : "/addresses/**" } } ] , "filters" : [ ] , "uri" : "lb://user-service" } , { "id" : "trade" , "predicates" : [ { "name" : "Path" , "args" : { "_genkey_0" : "/orders/**" } } ] , "filters" : [ ] , "uri" : "lb://trade-service" } , { "id" : "pay" , "predicates" : [ { "name" : "Path" , "args" : { "_genkey_0" : "/pay-orders/**" } } ] , "filters" : [ ] , "uri" : "lb://pay-service" } ]
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 @Component @Slf4j @RequiredArgsConstructor public class DynamicRouteLoader { private final NacosConfigManager nacosConfigManager; private final RouteDefinitionWriter writer; private final String dataId = "gateway-routes.json" ; private final String group = "DEFAULT_GROUP" ; private final Set<String> routeIds = new HashSet <>(); @PostConstruct public void initRouteConfigListener () throws NacosException { String configInfo = nacosConfigManager.getConfigService() .getConfigAndSignListener(dataId, group, 5000 , new Listener () { @Override public Executor getExecutor () { return null ; } @Override public void receiveConfigInfo (String configInfo) { updateConfigInfo(configInfo); } }); updateConfigInfo(configInfo); } public void updateConfigInfo (String configInfo) { log.debug("监听到路由配置信息:{}" , configInfo); List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class); for (String routeId : routeIds) { writer.delete(Mono.just(routeId)).subscribe(); } routeIds.clear(); for (RouteDefinition routeDefinition : routeDefinitions) { writer.save(Mono.just(routeDefinition)).subscribe(); routeIds.add(routeDefinition.getId()); } } }
海林小盆友
小盆友
本文采用 CC BY-NC-SA 4.0 许可协议