æ¬æè®°å½ä¸ä¸ææ¯å¦ä½ä½¿ç¨ Gateway æå»ºç½å ³æå¡åå®ç°å¨æè·¯ç±çï¼å¸®å©å¤§å®¶å¦ä¹ å¦ä½å¿«éæå»ºç½å ³æå¡ï¼äºè§£è·¯ç±ç¸å ³é ç½®ã
1ãæ°æ®åºè®¾è®¡
主表管çè·¯ç±é ç½®ï¼å表管çè·¯ç±åæ°é ç½®ã
-- å¯¼åº è¡¨ test.gateway_router ç»æ
CREATE TABLE IF NOT EXISTS `gateway_router` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`router_id` varchar(80) NOT NULL COMMENT 'è·¯ç±ID',
`uri` varchar(200) CHARACTER SET utf8 COLLATE utf8_german2_ci NOT NULL COMMENT 'è·¯ç±å°å',
`sort` tinyint(4) DEFAULT NULL COMMENT 'è·¯ç±é¡ºåº',
`type` tinyint(4) NOT NULL DEFAULT 1 COMMENT 'ç±»åï¼1-lb模å¼(é»è®¤)ï¼2-http模å¼',
`valid` tinyint(1) DEFAULT 0 COMMENT 'å¯ç¨ç¶æï¼0ç¦ç¨(é»è®¤)ï¼1å¯å¨',
`memo` varchar(50) CHARACTER SET utf8 COLLATE utf8_german2_ci DEFAULT NULL COMMENT '说æ',
`deleted` tinyint(1) DEFAULT 0 COMMENT 'é»è¾å é¤ï¼1-å é¤',
`create_at` datetime NOT NULL,
`update_at` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `router_id` (`router_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 COMMENT='ç½å
³è·¯ç±é
ç½®';
INSERT INTO `gateway_router` (`id`, `router_id`, `uri`, `sort`, `type`, `valid`, `memo`, `deleted`, `create_at`, `update_at`) VALUES
(1, 'generator', 'http://127.0.0.1:8001/', 1, 2, 1, '代ç çæå¨', 0, '2022-08-18 15:15:27', '2022-08-18 15:15:28'),
(2,', 1, 2, 1, 0, '2022-10-15 15:32:40', '2022-10-15 15:32:40');
-- å¯¼åº è¡¨ test.gateway_router_item ç»æ
CREATE TABLE IF NOT EXISTS `gateway_router_item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`router_id` varchar(80) NOT NULL DEFAULT '' COMMENT 'è·¯ç±ID',
`param_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_german2_ci NOT NULL COMMENT 'åæ°name',
`param_key` varchar(200) CHARACTER SET utf8 COLLATE utf8_german2_ci NOT NULL COMMENT 'åæ°key',
`param_value` varchar(50) CHARACTER SET utf8 COLLATE utf8_german2_ci DEFAULT NULL COMMENT 'åæ°value',
`type` tinyint(4) NOT NULL DEFAULT 1 COMMENT 'åæ°ç±»åï¼1为 predicateï¼2ä¸ºè¿ filter',
`valid` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'å¯ç¨ç¶æï¼0ç¦ç¨(é»è®¤)ï¼1å¯å¨',
`deleted` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'é»è¾å é¤ï¼1-å é¤',
`create_at` datetime NOT NULL,
`update_at` datetime NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COMMENT='ç½å
³è·¯ç±åæ°è¡¨';
INSERT INTO `gateway_router_item` (`id`, `router_id`, `param_name`, `param_key`, `param_value`, `type`, `valid`, `deleted`, `create_at`, `update_at`) VALUES
(1, 'generator', 'Path', 'pattern', '/generator/**', 1, 1, 0, '2022-10-14 21:09:59', '2022-10-14 21:10:00'),
(4, 'csdn', 'Path', 'pattern', '/csdn', 1, 1, 0, '2022-10-15 21:18:01', '2022-10-15 21:18:02');
2ãå¨æè·¯ç±å®ç°
ç¼åæè·¯ç±å®ç°ç±»ï¼å®ç° ApplicationEventPublisherAware æ¥å£ã
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.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.List;
/**
* å¨æè·¯ç±å®ç°
*
* @author H.Yang
* @date 2022/10/15
*/
@Slf4j
@Component
public class DynamicRouteService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@Autowired
private RedisRouteDefinitionRepository redisRouteDefinitionRepository;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* è·¯ç±å®ä¹
*
* @param routerId
* @param uri
* @param predicates
* @param filters
* @return
*/
public void getRouteDefinition(String routerId, URI uri, List<PredicateDefinition> predicates, List<FilterDefinition> filters) {
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.setId(routerId);
routeDefinition.setUri(uri);
routeDefinition.setPredicates(predicates);
routeDefinition.setFilters(filters);
this.addRoute(routeDefinition);
}
/**
* è°è¯å®ä¹
*
* @param key
* @param name
* @param val
* @return
*/
public PredicateDefinition getPredicateDefinition(String key, String name, String val) {
PredicateDefinition predicate = new PredicateDefinition();
// åç§°æ¯åºå®ç
predicate.setName(key);
predicate.addArg(name, val);
return predicate;
}
/**
* è¿æ»¤å¨å®ä¹
*
* @param key
* @param name
* @param val
* @return
*/
public FilterDefinition getFilterDefinition(String key, String name, String val) {
FilterDefinition filter = new FilterDefinition();
filter.setName(key);
filter.addArg(name, val);
return filter;
}
/**
* æ·»å è·¯ç±
*
* @param definition
*/
public void addRoute(RouteDefinition definition) {
redisRouteDefinitionRepository.save(Mono.just(definition)).subscribe();
}
/**
* åå¸
*/
public void publish() {
applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
}
public void cleanAll() {
redisRouteDefinitionRepository.cleanAll();
}
}
3ãé 置路ç±å卿¹å¼
import cn.hutool.json.JSONUtil;
import com.xh.jedis.template.JedisPoolRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.LinkedList;
import java.util.List;
/**
* é
置路ç±å卿¹å¼
*
* @author H.Yang
* @date 2022/10/15
*/
@Slf4j
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
public static final String GATEWAY_ROUTES = "gateway:routes";
@Autowired
private JedisPoolRepository jedisPoolRepository;
/**
* å¯å¨æ¶å°±å è½½å½åæ¹æ³
* <p>
* 请注æï¼æ¤æ¹æ³å¾éè¦ï¼ä»redisåè·¯ç±ä¿¡æ¯çæ¹æ³ï¼å®æ¹æ ¸å¿å
è¦ç¨ï¼æ ¸å¿è·¯ç±åè½é½æ¯ä»redisåç
*/
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
log.debug("loading route....");
List<RouteDefinition> routeDefinitions = new LinkedList<>();
jedisPoolRepository.hvals(GATEWAY_ROUTES).stream().forEach(item -> {
log.debug(item);
routeDefinitions.add(JSONUtil.toBean(item, RouteDefinition.class));
});
return Flux.fromIterable(routeDefinitions);
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(routeDefinition -> {
jedisPoolRepository.hset(GATEWAY_ROUTES, routeDefinition.getId(), JSONUtil.toJsonStr(routeDefinition));
return Mono.empty();
});
}
/**
* ç®å使ç¨çå
¨éæ´æ°ï¼æå¨å·æ°ç¼åï¼çæ¹å¼ï¼å æ¤å½åæ¹æ³ä¸ä¼è°ç¨å°
*
* @param routeId
* @return
*/
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id -> {
if (jedisPoolRepository.hexists(GATEWAY_ROUTES, id)) {
jedisPoolRepository.hdel(GATEWAY_ROUTES, id);
return Mono.empty();
}
return Mono.defer(() -> Mono.error(new NotFoundException("è·¯ç±æä»¶æ²¡ææ¾å°: " + routeId)));
});
}
/**
* æ¸
空ç¼å
*/
public void cleanAll() {
log.debug("clear router cache...");
jedisPoolRepository.del(GATEWAY_ROUTES);
}
}
4ãå·æ°é ç½®
@Autowired
private GatewayRouterService gatewayRouterService;
@Autowired
private GatewayRouterItemService gatewayRouterItemService;
@Autowired
private DynamicRouteService dynamicRouteService;
@Override
public void loadRouter() {
// æ¸
空ç¼å
dynamicRouteService.cleanAll();
// æ¥è¯¢è·¯ç±é
ç½®
Map<String, List<GatewayRouterItemEntity>> routerItemMap = gatewayRouterItemService.listValidAll().stream().collect(Collectors.groupingBy(item -> item.getRouterId(), Collectors.mapping(item -> item, Collectors.toList())));
gatewayRouterService.listValidAll().stream().forEach(item -> {
List<GatewayRouterItemEntity> routerItemList = routerItemMap.get(item.getRouterId());
if (routerItemList == null)
return;
// åå§å - è·¯ç±é
ç½®
this.routeDefinition(item, routerItemList);
});
// åå¸ - é
ç½®å¼å§çæ
dynamicRouteService.publish();
}
private void routeDefinition(GatewayRouterEntity item, List<GatewayRouterItemEntity> routerItemList) {
List<PredicateDefinition> predicates = new LinkedList<>();
List<FilterDefinition> filters = new ArrayList();
for (GatewayRouterItemEntity routerItem : routerItemList) {
if (routerItem.getType() == 1) {
predicates.add(dynamicRouteService.getPredicateDefinition(routerItem.getParamName(), routerItem.getParamKey(), routerItem.getParamValue()));
continue;
}
filters.add(dynamicRouteService.getFilterDefinition(routerItem.getParamName(), routerItem.getParamKey(), routerItem.getParamValue()));
}
URI uri = (item.getType() == 1) ? UriComponentsBuilder.fromUriString("lb://" + item.getUri()).build().toUri() : UriComponentsBuilder.fromHttpUrl(item.getUri()).build().toUri();
dynamicRouteService.getRouteDefinition(item.getRouterId(), uri, predicates, filters);
}