spring gateway 动态路由

时间:2024-11-11 09:34:00

##yml配置

spring:
  application:
    name: public-gateway
#  cloud:
#    gateway:
#      routes:
#        - id: mybatis-plus-test # 路由的唯一标识
#          uri: http://192.168.3.188:9898 # 目标服务的地址
#          predicates:
#            - Path=/test/** # 匹配以 /user/ 开头的请求路径
#          filters:
#            - AddRequestHeader=X-Request-Example, Example # 添加一个请求头
#            - AddRequestParameter=param1, value1 # 添加一个请求参数
server:
  port: 8180
logging:
  config: classpath:config/logback-spring.xml

##DynamicRoutesService动态路由

ApplicationEventPublisherAware得到publisher发布事件刷新路由缓存

ApplicationRunner设置路由

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
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.cloud.gateway.route.RouteLocator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
public class DynamicRoutesService implements ApplicationEventPublisherAware, ApplicationRunner {

    @Autowired
    private RouteLocator routeLocator;

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    private void loadDynamicRoutes() {
        routeDefinitionWriter.save(Mono.just(createRoute())).subscribe();
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        loadDynamicRoutes();
        publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    public RouteDefinition createRoute() {
        PredicateDefinition predicateDefinition = new PredicateDefinition();
        List<PredicateDefinition> predicates = new ArrayList<>();
        predicates.add(predicateDefinition);
        Map<String, String> argsPredicate = new LinkedHashMap<>();
        
        argsPredicate.put("key0", "/test/**");
        predicateDefinition.setName("Path");
        predicateDefinition.setArgs(argsPredicate);

        FilterDefinition filterDefinition = new FilterDefinition();
        List<FilterDefinition> filters = new ArrayList<>();
        filters.add(filterDefinition);
        Map<String, String> argsFilter = new LinkedHashMap<>();
        
        argsFilter.put("name", "X-Request-Example");
        argsFilter.put("value", "Example");

        filterDefinition.setName("AddRequestHeader");
        filterDefinition.setArgs(argsFilter);

        RouteDefinition routeDefinition = new RouteDefinition();
        routeDefinition.setUri(URI.create("http://192.168.3.104:9898"));
        routeDefinition.setOrder(1);
        routeDefinition.setId("mybatis-plus-test");
        routeDefinition.setPredicates(predicates);
        routeDefinition.setFilters(filters);
        return routeDefinition;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

}

##CachingRouteLocator刷新缓存源码

private final Map<String, List> cache = new ConcurrentHashMap<>();

@Override
	public void onApplicationEvent(RefreshRoutesEvent event) {
		try {
			fetch().collect(Collectors.toList()).subscribe(list -> Flux.fromIterable(list)
					.materialize().collect(Collectors.toList()).subscribe(signals -> {
						applicationEventPublisher
								.publishEvent(new RefreshRoutesResultEvent(this));
						cache.put(CACHE_KEY, signals);
					}, throwable -> handleRefreshError(throwable)));
		}
		catch (Throwable e) {
			handleRefreshError(e);
		}
	}

##fetch方法

private Flux<Route> fetch() {
		return this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE);
	}

##fetch方法通过CompositeRouteLocator获取路由

@Override
	public Flux<Route> getRoutes() {
		return this.delegates.flatMapSequential(RouteLocator::getRoutes);
	}