动态路由
? Gateway配置路由主要有两种方式:一种是yml配置文件,另一种是写在代码里。而无论哪种方式,启动网关后将无法修改路由配置,如有新服务要上线,则需要先把网关下线,修改yml配置后,再重启网关。
? Gateway提供了Endpoint断点,暴露路由信息,有获取所有路由,刷新路由,查看单个路由,删除路由等方法。要访问断点中的方法需要添加spring-boot-starter-actuator 注解,并在配置文件中暴露所有端点。
management:
endpoints:
web:
exposure:
include:
- '*'
health:
show-details: always
所需依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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>
1 创建基本模型
根据路由的结构创建模型(路由模型,断言模型,过滤器模型)
路由模型:
public class GatewayRouteDefinition {
private String id;
private List<GatewayPredicateDefinition> predicates = new ArrayList<>();
private List<GatewayFilterDefinition> filters = new ArrayList<>();
private String uri;
private int order = 0;
}
断言模型:
public class GatewayPredicateDefinition {
private String name;
private Map<String, String> args = new LinkedHashMap<String, String>();
}
过滤器模型:
public class GatewayFilterDefinition {
private String name;
private Map<String, String> args = new LinkedHashMap<>();
}
2 创建动态路由服务Service
动态路由服务主要提供:增加路由,修改路由,删除路由这三个服务,需要实现ApplicationEventPublisherAware接口。
DynamicRouteServiceImpl:
package com.lmc.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public String add(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
public String update(RouteDefinition definition) {
try {
delete(definition.getId());
} catch (Exception e) {
return "update fail, not find route routeId: " + definition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update route fail";
}
}
public Mono<ResponseEntity<Object>> delete(String id) {
return this.routeDefinitionWriter.delete(Mono.just(id)).then(Mono.defer(() -> {
return Mono.just(ResponseEntity.ok().build());
})).onErrorResume((t) -> {
return t instanceof NotFoundException;
}, (t) -> {
return Mono.just(ResponseEntity.notFound().build());
});
}
}
3 提供动态路由服务接口API
提供对外接口,可以通过接口对gateway的路由进行操作
package com.lmc.controller;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import com.lmc.definition.GatewayFilterDefinition;
import com.lmc.definition.GatewayPredicateDefinition;
import com.lmc.definition.GatewayRouteDefinition;
import com.lmc.service.DynamicRouteServiceImpl;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/route")
public class RouteController {
@Autowired
private DynamicRouteServiceImpl dynamicRouteService;
@PostMapping("/add")
public String add(@RequestBody GatewayRouteDefinition gwdefinition) {
System.out.println("add = " + gwdefinition.toString());
String flag = "fail";
try {
RouteDefinition definition = assembleRouteDefinition(gwdefinition);
flag = this.dynamicRouteService.add(definition);
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
@PostMapping("/routes/{id}")
public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
try {
return this.dynamicRouteService.delete(id);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@PostMapping("/update")
public String update(@RequestBody GatewayRouteDefinition gwdefinition) {
System.out.println("update = " + gwdefinition.toString());
RouteDefinition definition = assembleRouteDefinition(gwdefinition);
return this.dynamicRouteService.update(definition);
}
private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gwdefinition) {
RouteDefinition definition = new RouteDefinition();
definition.setId(gwdefinition.getId());
definition.setOrder(gwdefinition.getOrder());
List<PredicateDefinition> pdList = new ArrayList<PredicateDefinition>();
List<GatewayPredicateDefinition> gatewayPredicateDefinitionList = gwdefinition.getPredicates();
for (GatewayPredicateDefinition gPDefinition : gatewayPredicateDefinitionList) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setArgs(gPDefinition.getArgs());
predicate.setName(gPDefinition.getName());
pdList.add(predicate);
}
definition.setPredicates(pdList);
List<FilterDefinition> fdList = new ArrayList<>();
List<GatewayFilterDefinition> gatewayFilterDefinitionList = gwdefinition.getFilters();
for (GatewayFilterDefinition gFDefinition : gatewayFilterDefinitionList) {
FilterDefinition filter = new FilterDefinition();
filter.setArgs(gFDefinition.getArgs());
filter.setName(gFDefinition.getName());
fdList.add(filter);
}
definition.setFilters(fdList);
System.out.println("gatewayFilterDefinitionList = " + gatewayFilterDefinitionList.toString());
System.out.println("fdList = " + fdList.toString());
URI uri = null;
if (gwdefinition.getUri().startsWith("http")) {
uri = UriComponentsBuilder.fromHttpUrl(gwdefinition.getUri()).build().toUri();
} else {
uri = URI.create(gwdefinition.getUri());
}
definition.setUri(uri);
return definition;
}
}
以上配置完成发布服务之后,以后添加新服务就可以通过接口来动态操作路由。
|