赞
踩
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.gateway</groupId> <artifactId>code</artifactId> <version>0.0.1-SNAPSHOT</version> <name>gateway</name> <description>gateway</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <spring-boot.version>2.4.1</spring-boot.version> <spring-cloud.version>2020.0.0</spring-cloud.version> <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactI> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.4.1</version> <configuration> <mainClass>com.gateway.code.GatewayApplication</mainClass> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
server: #此处的8085端口号,就好像以前外置的tomcat的8080,让我们通过浏览器进行访问 #但此服务只是做了一个路由,它会将请求路由到其它微服务(一般是消费者)进行处理 port: 8085 spring: application: #微服务名 name: gateway cloud: nacos: discovery: #指定nacos注册中心的地址 server-addr: 127.0.0.1:8848 gateway: discovery: locator: #localhost:8085/provider/user/aa #localhost:8085/consumer/user/aa #是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false #为true代表开启基于服务发现的路由规则。 enabled: true #配置之后访问时service-id无需大写 lower-case-service-id: true # routes: # # 路由标识(id:标识,具有唯一性) # - id: user-consumer-api # #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死 # uri: lb://consumer # #优先级,越小越优先 # #order: 999 # #路由条件(predicates:断言) # predicates: # # 路径匹配, # - Path=/aa/** # filters: # #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo # #前缀过滤,请求地址:http://localhost:8084/usr/hello # #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务 # #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉 # - StripPrefix=1 # # 路由标识(id:标识,具有唯一性) # - id: user-provider-api # #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死 # uri: lb://provider # #优先级,越小越优先 # #order: 999 # #路由条件(predicates:断言) # predicates: # # 路径匹配, # - Path=/bb/cc/** # filters: # #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo # #前缀过滤,请求地址:http://localhost:8084/usr/hello # #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务 # #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉 # - StripPrefix=2 logging: level: #开启spring-Cloud-gateway的日志级别为debug,方便debug调试 org.springframework.cloud.gateway: trace org.springframework.http.server.reactive: debug org.springframework.web.reactive: debug reactor.ipc.netty: debug #springboot监控Actuator,暴露所有端点 management: endpoints: web: exposure: include: '*' #自定义配置 gateway: nacos: server-addr: ${spring.cloud.nacos.discovery.server-addr} # namespace: xxx-xx-xx-xx data-id: dynamic-routing.json group: DEFAULT_GROUP
server: #此处的8085端口号,就好像以前外置的tomcat的8080,让我们通过浏览器进行访问 #但此服务只是做了一个路由,它会将请求路由到其它微服务(一般是消费者)进行处理 port: 8085 spring: application: #微服务名 name: gateway cloud: nacos: discovery: #指定nacos注册中心的地址 server-addr: 127.0.0.1:8848 gateway: discovery: locator: #localhost:8085/provider/user/aa #localhost:8085/consumer/user/aa #是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false #为true代表开启基于服务发现的路由规则。 enabled: false #配置之后访问时service-id无需大写 lower-case-service-id: true routes: # 路由标识(id:标识,具有唯一性) - id: user-consumer-api #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死 uri: lb://consumer #优先级,越小越优先 #order: 999 #路由条件(predicates:断言) predicates: # 路径匹配, #localhost:8085/user/aa 不能进 #localhost:8085/cum/user/aa 能进 - Path=/cum/** filters: #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo #前缀过滤,请求地址:http://localhost:8084/usr/hello #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务 #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉 - StripPrefix=1 # 路由标识(id:标识,具有唯一性) - id: user-provider-api #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死 uri: lb://provider #优先级,越小越优先 #order: 999 #路由条件(predicates:断言) predicates: # 路径匹配, #localhost:8085/api/prv/user/aa - Path=/api/prv/** filters: #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo #前缀过滤,请求地址:http://localhost:8084/usr/hello #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务 #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉 - StripPrefix=2 logging: level: #开启spring-Cloud-gateway的日志级别为debug,方便debug调试 org.springframework.cloud.gateway: trace org.springframework.http.server.reactive: debug org.springframework.web.reactive: debug reactor.ipc.netty: debug #springboot监控Actuator,暴露所有端点 management: endpoints: web: exposure: include: '*' #自定义配置 gateway: nacos: server-addr: ${spring.cloud.nacos.discovery.server-addr} # namespace: xxx-xx-xx-xx data-id: dynamic-routing.json group: DEFAULT_GROUP
gateway :nacos :server-addr : $ { spring.cloud.nacos.discovery.server-addr }# namespace: xxx-xx-xx-xxdata-id : dynamic-routing.jsongroup : DEFAULT_GROUP配合读取类使用
{
"refreshGatewayRoute": true,
"routeList": [
{
"id": "consumer-api",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/cum/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"uri": "lb://consumer",
"order": 0
},
{
"id": "provider-api",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/api/pvr/**"
}
}
],
"filters": [
{
"name": "StripPrefix",
"args": {
"_genkey_0": "2"
}
}
],
"uri": "lb://provider",
"order": 0
}
]
}
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.35</version> </dependency>
- package com.gateway.code.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;
-
- }
(实体类中的属性对应配置内容中的json数据)
- package com.gateway.code.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 {
-
- //路由id
- private String id;
-
- //路由断言集合
- private List<PredicateEntity> predicates = new ArrayList<>();
-
- //路由过滤器集合
- private List<FilterEntity> filters = new ArrayList<>();
-
- //路由转发的目标uri
- private String uri;
-
- //路由执行的顺序
- private int order = 0;
-
- }
- package com.gateway.code.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 {
-
- //过滤器对应的Name
- private String name;
-
- //路由规则
- private Map<String, String> args = new LinkedHashMap<>();
-
- }
- package com.gateway.code.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 {
-
- //断言对应的Name
- private String name;
-
- //断言规则
- private Map<String, String> args = new LinkedHashMap<>();
-
- }
- package com.gateway.code;
-
- 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 com.gateway.code.pojo.FilterEntity;
- import com.gateway.code.pojo.GatewayNacosProperties;
- import com.gateway.code.pojo.PredicateEntity;
- import com.gateway.code.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 {
-
- @Autowired
- private RouteDefinitionWriter routeDefinitionWriter;
-
- @Autowired
- private GatewayNacosProperties gatewayProperties;
-
- private ApplicationEventPublisher applicationEventPublisher;
-
- @Override
- public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
- this.applicationEventPublisher = applicationEventPublisher;
- }
-
- /**
- * 这个方法主要负责监听Nacos的配置变化,这里先使用参数构建一个ConfigService,
- * 再使用ConfigService开启一个监听,
- * 并且在监听的方法中刷新路由信息。
- */
- @Bean
- public 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);
- if(json == null){
- return;
- }
- this.parseJson(json);
-
- //添加监听器,监听nacos中的数据修改事件
- configService.addListener(gatewayProperties.getDataId(), gatewayProperties.getGroup(), new Listener() {
- @Override
- public Executor getExecutor() {
- return null;
- }
-
- /**
- * 用于接收远端nacos中数据修改后的回调方法
- */
- @Override
- public 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);
- }
-
- }
-
- /**
- * 根据自己的路由实体类生成gateway的路由定义对象
- */
- public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {
-
- RouteDefinition definition = new RouteDefinition();
-
- // ID
- definition.setId(routeEntity.getId());
-
- // Predicates
- List<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);
-
- // Filters
- List<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);
-
- // URI
- URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
- definition.setUri(uri);
-
- return definition;
- }
-
- }
运行效果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。