🥳🥳Welcome Huihui's Code World ! !🥳🥳
接下来看看由辉辉所写的关于SpringCloud的相关操作吧
目录
🥳🥳Welcome Huihui's Code World ! !🥳🥳
一.网关组件是什么
二. 网关组件的详解
生活例子
例子剖析
三.代码演示【网关的三种使用方式】
0.配置
1.根据服务名访问
2.根据路径访问
3.动态路由
路由
断言
过滤器
配置类
路由处理类
注意点:
一.网关组件是什么
网关(Gateway)组件是指用于构建具有统一入口的微服务架构中的一个组件,它可以实现动态路由、负载均衡、熔断、安全控制等功能。在微服务架构中,每个服务都有自己的入口,客户端需要知道每个服务的地址和端口号才能访问它们。而网关组件可以为所有服务提供一个统一的入口,客户端只需要知道网关的地址和端口号,就可以通过网关访问所有的服务。
常见的网关组件包括Zuul、Spring Cloud Gateway、Kong、Nginx等。这些网关组件都具有一定的功能和特点,可以根据具体需求选择合适的网关组件。
Spring Cloud Gateway
三大核心概念
1️⃣路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL、一组断言工厂和一 组Filter组成。如果断言为真,则说明请求URL和配置的路由匹配。
2️⃣断言(Predicate):Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是 Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配 来自http Request中的任何信息,比如请求头和参数等。
3️⃣过滤器(Filter):一个标准的Spring WebFilter,Spring Cloud Gateway中的Filter分为两种类型: Gateway Filter和Global Filter。过滤器Filter可以对请求和响应进行处理
二. 网关组件的详解
这里举一个生活中的例子,来帮助大家理解一下网关这个组件
生活例子
假设你住在一个小区里,每个家庭都有自己的门禁系统和电话系统。
现在,你想要给小区外的朋友打电话
但是你不知道他们具体的电话号码,只知道他们的姓名。这时候,你需要通过小区的门禁系统(网关)来连接到外部电话网络,然后通过输入朋友的姓名(数据)来查找他们的电话号码(其他网络)并打通电话。
例子剖析
在这个例子中,小区的门禁系统就是一个网关,它连接了小区内部的电话系统和外部的电话网络,帮助你实现了与外部电话网络的通信。类似地,在计算机网络中,网关起到了连接不同网络或协议的桥梁作用,使得数据能够在它们之间进行传输和转换。
三.代码演示【网关的三种使用方式】
0.配置
在进行下面三种方式的讲解之前,咱先得将文件都给配置好
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
然后需要新建一个项目,我这里建的是一个springboot的项目
1.根据服务名访问
这里只需要配置好就行了
discovery:#根据服务名locator:#true代表开启基于服务发现的路由规则enabled: true#配置之后访问时service-id无需大写lower-case-service-id: true
然后就可以按照nacos中的服务器名中进行访问了
2.根据路径访问
其中我是没有使用负载均衡,如果使用了负载均衡,那么在那个uri那里写的就是负载均衡的格式
单体
routes:- id: user-consumer-api#目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死uri: http://localhost:8081#路由条件(predicates:断言)predicates:# 路径匹配,- Path=/aa/**filters:- StripPrefix=1
负载均衡
routes:- id: user-consumer-api#目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死uri: lb//consumer#路由条件(predicates:断言)predicates:# 路径匹配,- Path=/aa/**filters:- StripPrefix=1
3.动态路由
这里就是自己定义了一个规则,然后需要编写路由,断言,过滤器,以及读取配置的文件的配置类,还有关于路由操作的处理类
#自定义配置 gateway:nacos:server-addr: ${spring.cloud.nacos.server-addr}# namespace: xxx-xx-xx-xxdata-id: dynamic-routing.jsongroup: DEFAULT_GROUP
路由
package gateway.demo.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors;import java.util.ArrayList; import java.util.List;/*** @author hgh*/ @SuppressWarnings("all") @Data @NoArgsConstructor @AllArgsConstructor @Accessors(chain = true) public class RouteEntity {//路由idprivate String id;//路由断言集合private List<PredicateEntity> predicates = new ArrayList<>();//路由过滤器集合private List<FilterEntity> filters = new ArrayList<>();//路由转发的目标uriprivate String uri;//路由执行的顺序private int order = 0;}
断言
package gateway.demo.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors;import java.util.LinkedHashMap; import java.util.Map;/*** @author hgh*/ @SuppressWarnings("all") @Data @NoArgsConstructor @AllArgsConstructor @Accessors(chain = true) public class PredicateEntity {//断言对应的Nameprivate String name;//断言规则private Map<String, String> args = new LinkedHashMap<>();}
过滤器
package gateway.demo.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors;import java.util.LinkedHashMap; import java.util.Map;/*** @author hgh*/ @SuppressWarnings("all") @Data @NoArgsConstructor @AllArgsConstructor @Accessors(chain = true) public class FilterEntity {//过滤器对应的Nameprivate String name;//路由规则private Map<String, String> args = new LinkedHashMap<>();}
配置类
package gateway.demo.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component;@SuppressWarnings("all") @Data @NoArgsConstructor @AllArgsConstructor @Accessors(chain = true) @ConfigurationProperties(prefix = "gateway.nacos") @Component public class GatewayNacosProperties {private String serverAddr;private String dataId;private String namespace;private String group;}
路由处理类
package gateway.demo;import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; import com.fasterxml.jackson.databind.ObjectMapper; import gateway.demo.pojo.FilterEntity; import gateway.demo.pojo.GatewayNacosProperties; import gateway.demo.pojo.PredicateEntity; import gateway.demo.pojo.RouteEntity; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionWriter; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.util.UriComponentsBuilder; import reactor.core.publisher.Mono;import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.Executor;/*** 此类实现了Spring Cloud Gateway + nacos 的动态路由,* 它实现一个Spring提供的事件推送接口ApplicationEventPublisherAware*/ @SuppressWarnings("all") @Slf4j @Component public class DynamicRoutingConfig implements ApplicationEventPublisherAware {@Autowiredprivate RouteDefinitionWriter routeDefinitionWriter;@Autowiredprivate GatewayNacosProperties gatewayProperties;@Autowiredprivate ObjectMapper mapper;private ApplicationEventPublisher applicationEventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}/*** 这个方法主要负责监听Nacos的配置变化,这里先使用参数构建一个ConfigService,* 再使用ConfigService开启一个监听,* 并且在监听的方法中刷新路由信息。*/@Beanpublic void refreshRouting() throws NacosException {//创建Properties配置类Properties properties = new Properties();System.out.println(gatewayProperties);//设置nacos的服务器地址,从配置类GatewayProperties中获取properties.put(PropertyKeyConst.SERVER_ADDR, gatewayProperties.getServerAddr());//设置nacos的命名空间,表示从具体的命名空间中获取配置信息,不填代表默认从public获得if (gatewayProperties.getNamespace() != null) {properties.put(PropertyKeyConst.NAMESPACE, gatewayProperties.getNamespace());}//根据Properties配置创建ConfigService类ConfigService configService = NacosFactory.createConfigService(properties);//获得nacos中已有的路由配置String json = configService.getConfig(gatewayProperties.getDataId(), gatewayProperties.getGroup(), 5000);this.parseJson(json);//添加监听器,监听nacos中的数据修改事件configService.addListener(gatewayProperties.getDataId(), gatewayProperties.getGroup(), new Listener() {@Overridepublic Executor getExecutor() {return null;}/*** 用于接收远端nacos中数据修改后的回调方法*/@Overridepublic void receiveConfigInfo(String configInfo) {log.warn(configInfo);//获取nacos中修改的数据并进行转换parseJson(configInfo);}});}/*** 解析从nacos读取的路由配置信息(json格式)*/public void parseJson(String json) {log.warn("从Nacos返回的路由配置(JSON格式):" + json);boolean refreshGatewayRoute = JSONObject.parseObject(json).getBoolean("refreshGatewayRoute");if (refreshGatewayRoute) {List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(json).getString("routeList")).toJavaList(RouteEntity.class);for (RouteEntity route : list) {update(assembleRouteDefinition(route));}} else {log.warn("路由未发生变更");}}/*** 路由更新*/public void update(RouteDefinition routeDefinition) {try {this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));log.warn("路由删除成功:" + routeDefinition.getId());} catch (Exception e) {log.error(e.getMessage(), e);}try {routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));log.warn("路由更新成功:" + routeDefinition.getId());} catch (Exception e) {log.error(e.getMessage(), e);}}/*** 路由定义*/public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {RouteDefinition definition = new RouteDefinition();// IDdefinition.setId(routeEntity.getId());// PredicatesList<PredicateDefinition> pdList = new ArrayList<>();for (PredicateEntity predicateEntity : routeEntity.getPredicates()) {PredicateDefinition predicateDefinition = new PredicateDefinition();predicateDefinition.setArgs(predicateEntity.getArgs());predicateDefinition.setName(predicateEntity.getName());pdList.add(predicateDefinition);}definition.setPredicates(pdList);// FiltersList<FilterDefinition> fdList = new ArrayList<>();for (FilterEntity filterEntity : routeEntity.getFilters()) {FilterDefinition filterDefinition = new FilterDefinition();filterDefinition.setArgs(filterEntity.getArgs());filterDefinition.setName(filterEntity.getName());fdList.add(filterDefinition);}definition.setFilters(fdList);// URIURI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();definition.setUri(uri);return definition;}}
注意点:
还有就是这个文件中如果你使用的是负载均衡,那么uri也是需要写负载均衡的,如果不是的话,那就写的需要访问服务的路径【我的这个是单体的,不是负载均衡的】
{"refreshGatewayRoute": true,"routeList": [{"id": "consumer-api","predicates": [{"name": "Path","args": {"_genkey_0": "/con/**"}}],"filters": [{"name": "StripPrefix","args": {"_genkey_0": "1"}}],"uri": "http://localhost:8081","order": 0},{"id": "provider-api","predicates": [{"name": "Path","args": {"_genkey_0": "/pro/**"}}],"filters": [{"name": "StripPrefix","args": {"_genkey_0": "1"}}],"uri": "http://localhost:8082","order": 0}] }
当我们去更改nacos中的配置时,这个也是会实时加载的,这个都是写在那个路由处理类中
好啦,今天的分享就到这了,希望能够帮到你呢!😊😊