처음 두, 주로 직접 운영 엔티티 클래스와 테이블을 작성하는
스토리지 클러스터링을위한 동적 라우팅 게이트웨이 [두] 라우팅, 게이트웨이 게이트웨이 동적 라우팅 구성, 사용의 MySQL [SpringCloud는 빌드 워크 분산]
스토리지 클러스터링을위한 동적 라우팅 게이트웨이 라우팅, 게이트웨이 게이트웨이 동적 라우팅 구성, 사용의 MySQL [SpringCloud 빌드 워크 분산] [A]
다음의 주요 지침은 동적 로딩의 게이트웨이를 구성 할 수 있습니다.
찾을 수있는 스프링 클라우드 게이트웨이 소스를 분석함으로써, 기본 구현 클래스는 RouteDefinitionWriter InMemoryRouteDefinitionRepository는 그림과 같습니다 :
RouteDefinitionRepository 继承了RouteDefinitionWriter,是 Spring Cloud Gateway官方预留的接口。从而可以通过下面两种方式来实现集群下的动态路由修改:RouteDefinitionWriter 接口和 RouteDefinitionRepository 接口。在这里推荐实现RouteDefinitionRepository 这个接口,从数据库或者从配置中心获取路由进行动态配置。
여기 내 MySQL의 구현 클래스에 직접 부착 : MysqlRouteDefinitionRepository
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.keda.gateway.entity.DynamicRouteVo;
import com.keda.gateway.entity.GatewayDynamicRoute;
import com.keda.gateway.service.IGatewayDynamicRouteService;
import com.keda.gateway.struts.DynamicRouteStruts;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @Author: seowen
* @Date: 2019/12/19 15:27
* @Version 1.0
*/
@Component
public class MysqlRouteDefinitionRepository implements RouteDefinitionRepository {
@Autowired
private IGatewayDynamicRouteService routeService;
/**
* Gateway启动的时候,会加载这个方法
* @return
*/
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
//从数据库中,获取我们自定义的 路由信息数据
List<GatewayDynamicRoute> listByEnable = routeService.getListByEnable(true);
if (CollectionUtils.isNotEmpty(listByEnable)){
//转换成 RouteDefinition 集合后,返回
return Flux.fromIterable(this.toRouteList(listByEnable));
}
//如果 数据库为 空,则返回一个 空的集合
return Flux.fromIterable(new ArrayList<RouteDefinition>());
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return null;
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return null;
}
/**
* 转换成 List<RouteDefinition>
* @param listByEnable
* @return
*/
private List<RouteDefinition> toRouteList(List<GatewayDynamicRoute> listByEnable){
List<RouteDefinition> routeList = new ArrayList<>();
/**
* 循环转换:
* 因为数据库中,Predicates 和 Filters 存储的 json字符串。所以,得先转换成 对应的 vo.
* 然后在转换成 List<PredicateDefinition>和 List<FilterDefinition>
*/
listByEnable.stream().forEach(gw->{
RouteDefinition r = new RouteDefinition();
r.setUri(DynamicUtil.getUri(gw.getUri()));
r.setOrder(gw.getOrder());
r.setId(gw.getRouteId());
r.setPredicates(DynamicRouteStruts.INSTANCES.toPredicateDefinition(JSONArray.parseArray(gw.getPredicates(), DynamicRouteVo.PredicateDefinitionVo.class)));
r.setFilters(DynamicRouteStruts.INSTANCES.toFilterDefinition(JSONArray.parseArray(gw.getFilters(),DynamicRouteVo.FilterDefinitionVo.class)));
routeList.add(r);
});
return routeList;
}
}
MysqlRouteDefinitionRepository 类写好后,还不行。 我们需要当每次操作 动态有路由表,都希望 gateway网关,重新加载 路由数据。 这个时候,我们就需要一个spring事件来支持。
DynamicRouteServiceImpl 类,就是我的 事件事件
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.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
/**
* @Author: seowen
* @Date: 2019/12/19 15:49
* @Version 1.0
*/
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
/**
* 增加路由
* @param routeDefinition
* @return
*/
public String add(RouteDefinition routeDefinition){
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.doLoad();
return "success";
}
/**
* 更新路由
*/
public String update(RouteDefinition definition) {
try {
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
} catch (Exception e) {
return "update fail,not find route routeId: " + definition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.doLoad();
return "success";
} catch (Exception e) {
return "update route fail";
}
}
/**
* 删除路由
*
*/
public String delete(String id) {
// return this.routeDefinitionWriter.delete(Mono.just(id)).then(Mono.defer(()->Mono.just(ResponseEntity.ok().build())))
// .onErrorResume(t -> t instanceof NotFoundException,t -> Mono.just(ResponseEntity.notFound().build()));
try {
this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
this.doLoad();
} catch (Exception e) {
e.printStackTrace();
return "delete fail,not find route routeId: " + id;
}
return "delete success";
}
/**
* 重新刷新 路由
*/
public String doLoad() {
try {
this.publisher.publishEvent(new RefreshRoutesEvent(this));
}catch (Exception e){
e.printStackTrace();
return "load fail";
}
return "load success";
}
}
우리는 각 데이터베이스 작업 후에는 라우팅을 새로 고치려면이 doLoad () 메서드를 호출해야합니다
추가 방법 GatewayDynamicRouteController로
/**
* 增加路由
* @param routeBean
* @return
*/
@PostMapping("/add")
public String add(@RequestBody DynamicRouteVo.RouteBean routeBean){
service.saveOne(DynamicRouteStruts.INSTANCES.toGatewayDynamicRoute(routeBean));
return this.dynamicRouteService.doLoad();
}
특별 참고 사항 :
{
"routeId":"keda-creditcard",
"uri":"lb://KEDA-CREDITCARD",
"order":"1",
"enable":"true",
"predicates":[
{
"name": "Path",
"args": {
"_genkey_0": "/main/**"
}
}
],
"filters":[
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
},
{
"name": "Retry",
"args": {
"retries": "3",
"series.0": "SERVER_ERROR",
"methods.0": "GET",
"methods.1": "POST"
}
}
]
}
위, 요청 매개 변수 :
라우팅 정보를 제공합니다. 일반적 = 값 이름 형태.
위의 경로 및 StripPrefix은 일반입니다 이름 속성 이름 . 특히 참고로,에 대응하는 값이다 "/ / ** 주" 와 "1" . 경우 게이트웨이 정적 경로 구성하겠습니다 직접 YML 파일, 라우팅 정보, 도시 된 바와 같이
![](https://img-blog.csdnimg.cn/20200103163855671.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjY5NzA3NA==,size_16,color_FFFFFF,t_70)
때 술어 및 필터링 노드의 구성이 간단하게 이름 = 값 시간. 프레스 할 게이트웨이 넣을 때 "="(즉 숯 61)을 분할한다. 그 다음에 값 "," 문자열로 분할 어레이 . 그리고, 「로 배열을 반복 _genkey_ "접두사 + 배열 첨자 후에는 열쇠이다. 밸류 값.
지도 인수해야 할
소스는 다음과 같습니다 :
따라서 우리는 경로를 추가, 또한이 규칙을 준수합니다. 예를 들면 :
"name": "Path",
"args": {
"_genkey_0": "/main/**"
}
경로가 추가 될 때, 인수 속성 및 상응하는 키있다 : 값 쌍하면 키 복합 (즉, 모음) 인 경우.
즉, 해당 키를 "키를 누르십시오. 작은 기호"표현하는 것입니다. 예를 들면 :
"name": "Retry",
"args": {
"retries": "3",
"series.0": "SERVER_ERROR",
"methods.0": "GET",
"methods.1": "POST"
}