路由 订阅
路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程 [1]  。路由工作在OSI参考模型第三层——网络层的数据包转发设备。路由器通过转发数据包来实现网络互连。虽然路由器可以支持多种协议(如TCP/IP、IPX/SPX、AppleTalk等协议),但是在我国绝大多数路由器运行TCP/IP协议。路由器通常连接两个或多个由IP子网或点到点协议标识的逻辑端口,至少拥有1个物理端口。路由器根据收到数据包中的网络层地址以及路由器内部维护的路由表决定输出端口以及下一跳地址,并且重写链路层数据包头实现转发数据包。路由器通过动态维护路由表来反映当前的网络拓扑,并通过网络上其他路由器交换路由和链路信息来维护路由表。 展开全文
路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程 [1]  。路由工作在OSI参考模型第三层——网络层的数据包转发设备。路由器通过转发数据包来实现网络互连。虽然路由器可以支持多种协议(如TCP/IP、IPX/SPX、AppleTalk等协议),但是在我国绝大多数路由器运行TCP/IP协议。路由器通常连接两个或多个由IP子网或点到点协议标识的逻辑端口,至少拥有1个物理端口。路由器根据收到数据包中的网络层地址以及路由器内部维护的路由表决定输出端口以及下一跳地址,并且重写链路层数据包头实现转发数据包。路由器通过动态维护路由表来反映当前的网络拓扑,并通过网络上其他路由器交换路由和链路信息来维护路由表。
信息
外文名
routing
概    念
工程术语
特    点
高效简单
中文名
路由
原理算法
确定最佳路径
路由概念
1、路由是指路由器从一个接口上收到数据包,根据数据 包的目的地址进行定向并转发到另一个接口的过程。路由通常与桥接来对比,在粗心的人看来,它们似乎完成的是同样的事。它们的主要区别在于桥接发生在OSI参考模型的第二层(数据链路层),而路由发生在第三层(网络层)。这一区别使二者在传递信息的过程中使用不同的信息,从而以不同的方式来完成其任务。路由的话题早已在计算机界出现,但直到八十年代中期才获得商业成功。究其主要原因是七十年代的网络普遍很简单,发展到后来大型的网络才较为普遍。2、工程术语。指道路情况,包括道路宽度、深度、方向等信息。
收起全文
精华内容
下载资源
问答
  • SpringCloudGateway动态路由(Redis持久化)以及请求到寻找路由的流程 1、路由加载流程简述 /** * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)} * 2、路由加载器...

    SpringCloudGateway动态路由(Redis持久化)以及请求到寻找路由的流程

    1、路由加载流程简述

    /**
         * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         * 2、路由加载器获取路由 {@link RouteLocator#getRoutes()} ;{@link RouteLocator}注入到Spring容器的是统一入口{@link CachingRouteLocator},
         *    {@link CompositeRouteLocator#getRoutes()} 在 {@link GatewayAutoConfiguration#cachedCompositeRouteLocator(List)} 注入到Spring容器中,
         * 3、路由定义信息加载器 方法cachedCompositeRouteLocator 中 List<RouteLocator> routeLocators 中,
         *    其中之一{@link RouteDefinitionRouteLocator}
         *    在{@link GatewayAutoConfiguration#routeDefinitionRouteLocator(GatewayProperties, List, List,RouteDefinitionLocator, ConfigurationService)} 注入到Spring容器中,
         *    其中 {@link RouteDefinitionLocator}(路由定义信息加载器)是统一入口 {@link CompositeRouteDefinitionLocator} 在{@link GatewayAutoConfiguration#routeDefinitionLocator(List)}注入到Spring容器中,
         *    其中 List<RouteDefinitionLocator> routeDefinitionLocators 包含
         *    读取配置文件的 {@link GatewayAutoConfiguration#propertiesRouteDefinitionLocator(GatewayProperties)}
         *    不存在持久化bean的时候 {@link GatewayAutoConfiguration#inMemoryRouteDefinitionRepository()}
         * 4、加载路由定义信息 {@link RouteDefinitionLocator#getRouteDefinitions()} {@link CompositeRouteDefinitionLocator#getRouteDefinitions()} 会统一加载,所有的 RouteDefinitionLocator bean
         *
         * 流程如下 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         *  {@link RouteLocator#getRoutes()} --[{@link CompositeRouteLocator#getRoutes()} {@link CachingRouteLocator#getRoutes()} 主要
         *  {@link RouteDefinitionRouteLocator#getRoutes()},初始化过滤器、断言等都在此类 ]
         *  {@link RouteDefinitionRouteLocator} 中的{@link RouteDefinitionLocator#getRouteDefinitions()}获取路由信息,{@link RouteDefinitionRouteLocator#convertToRoute(RouteDefinition)}
         *  路由信息转换为路由
         *
         *  RoutePredicateHandlerMapping 对应的映射,访问一次都会加载一次
         * @return
         */
    

    2、动态路由,redis存储

    • Controller
    @RestController
    public class GatewayRouteController extends GatewayBaseController{
    
        @Autowired
        DynamicRouteService routeService;
        @Autowired
        GatewayAppRouteRedisRepository redisRepository;
    
    //    @PostMapping(value = "add", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    //    public Response save(@RequestBody GatewayRouteDefinition definition) {
    //        routeService.save(definition);
    //        return Response.success();
    //    }
    
        @PostMapping("route/save_or_update")
        public Mono<RestResult> update(@RequestBody GatewayAppRoute definition) {
            routeService.update(definition);
            redisRepository.update(definition);
            return Mono.just(TRestBuilder.success());
        }
    
    
        @DeleteMapping("route/{id}")
        public Mono<RestResult> delete(@PathVariable("id") String id) {
            routeService.delete(id);
            redisRepository.delete(id);
            return Mono.just(TRestBuilder.success());
        }
    
        @PostMapping("routes")
        public Mono<RestResult<List<GatewayAppRoute>>> list() {
            return Mono.just(TRestBuilder.success(redisRepository.routeViews()));
        }
    }
    
    • 动态路由
    /**
     * 动态路由信息
     */
    public class DynamicRouteService implements ApplicationEventPublisherAware {
        @Autowired
        RouteDefinitionRepository routeDefinitionRepository;// 实现redis存储
    
        private ApplicationEventPublisher publisher;
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
         this.publisher=applicationEventPublisher;
        }
    
        // 发布事件,刷新路由,实现动态路由
        private void publish() {
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
        }
    
        public void save(GatewayAppRoute definition){
            RouteDefinition routeDefinition=definition.routeDefinition();
            routeDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
            publish();
        }
    
    
        public void update(GatewayAppRoute definition){
            RouteDefinition routeDefinition=definition.routeDefinition();
            routeDefinitionRepository.delete(Mono.just(definition.getServiceId()));
            routeDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
            publish();
        }
    
    
        public void delete(String serviceId){
            routeDefinitionRepository.delete(Mono.just(serviceId));
            publish();
        }
    }
    
    • Redis持久化
    /**
     * 路由存储 redis
     */
    public class RouteDefinitionRedisRepository implements RouteDefinitionRepository,RouteRepository {
        final static String GATEWAY_ROUTES = "GATEWAY:ROUTE";
        @Autowired
        RedisCache redisCache;//redis操作,Redistemplate
    
        /**
         * 从redis加在路由信息
         * @return
         */
        public Map<String,RouteDefinition> loadRoute() {
            Map<String, RouteDefinition> data = redisCache.getCacheMap(GATEWAY_ROUTES, RouteDefinition.class);
            return data;
        }
    
        /**
         * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         * 2、路由加载器获取路由 {@link RouteLocator#getRoutes()} ;{@link RouteLocator}注入到Spring容器的是统一入口{@link CachingRouteLocator},
         *    {@link CompositeRouteLocator#getRoutes()} 在 {@link GatewayAutoConfiguration#cachedCompositeRouteLocator(List)} 注入到Spring容器中,
         * 3、路由定义信息加载器 方法cachedCompositeRouteLocator 中 List<RouteLocator> routeLocators 中,
         *    其中之一{@link RouteDefinitionRouteLocator}
         *    在{@link GatewayAutoConfiguration#routeDefinitionRouteLocator(GatewayProperties, List, List,RouteDefinitionLocator, ConfigurationService)} 注入到Spring容器中,
         *    其中 {@link RouteDefinitionLocator}(路由定义信息加载器)是统一入口 {@link CompositeRouteDefinitionLocator} 在{@link GatewayAutoConfiguration#routeDefinitionLocator(List)}注入到Spring容器中,
         *    其中 List<RouteDefinitionLocator> routeDefinitionLocators 包含
         *    读取配置文件的 {@link GatewayAutoConfiguration#propertiesRouteDefinitionLocator(GatewayProperties)}
         *    不存在持久化bean的时候 {@link GatewayAutoConfiguration#inMemoryRouteDefinitionRepository()}
         * 4、加载路由定义信息 {@link RouteDefinitionLocator#getRouteDefinitions()} {@link CompositeRouteDefinitionLocator#getRouteDefinitions()} 会统一加载,所有的 RouteDefinitionLocator bean
         *
         * 流程如下 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         *  {@link RouteLocator#getRoutes()} --[{@link CompositeRouteLocator#getRoutes()} {@link CachingRouteLocator#getRoutes()} 主要
         *  {@link RouteDefinitionRouteLocator#getRoutes()},初始化过滤器、断言等都在此类 ]
         *  {@link RouteDefinitionRouteLocator} 中的{@link RouteDefinitionLocator#getRouteDefinitions()}获取路由信息,{@link RouteDefinitionRouteLocator#convertToRoute(RouteDefinition)}
         *  路由信息转换为路由
         *
         *  RoutePredicateHandlerMapping 对应的映射,访问一次都会加载一次
         * @return
         */
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
            List<RouteDefinition> routeDefinitions = new ArrayList<>();
            Map<String, RouteDefinition> data = loadRoute();
            if (!CollectionUtils.isEmpty(data)) {
                data.forEach((K, V) -> routeDefinitions.add(V));
            }
            return Flux.fromIterable(routeDefinitions);
        }
    
        @Override
        public Mono<Void> save(Mono<RouteDefinition> route) {
            return route.flatMap(routeDefinition -> {
                redisCache.putDataToCacheMap(GATEWAY_ROUTES, routeDefinition.getId(), routeDefinition);
                return Mono.empty();
            });
        }
    
        @Override
        public Mono<Void> delete(Mono<String> routeId) {
            return routeId.flatMap(id -> {
                if (redisCache.cacheMapHasKey(GATEWAY_ROUTES, id)) {
                    redisCache.deleteDataFromCacheMap(GATEWAY_ROUTES, id);
                    return Mono.empty();
                }
                return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition not found: " + routeId)));
            });
        }
    
        @Override
        public List<RouteDefinition> loadRoutes() {
            Map<String,RouteDefinition> data=loadRoute();
            return CollectionUtils.isEmpty(data)?new ArrayList<>():new ArrayList<>(data.values());
        }
    }
    
    
    • GatewayAppRoute
    /**
     * APP 配置信息
     */
    @Data
    public class GatewayAppRoute {
        /**
         * 服务状态
         */
        private int serviceStatus;
        /**
         * 服务名称
         */
        @NotBlank(message = "serviceName不能为空")
        private String serviceName;
        /**
         * 服务版本号
         */
        @NotBlank(message = "serviceVersion不能为空")
        private String serviceVersion;
        /**
         * 路由ID(服务ID)
         */
        @NotBlank(message = "serviceId不能为空")
        private String serviceId;
        /**
         * 路由断言集合配置
         */
        @NotEmpty(message = "predicates不能为空")
        private List<GatewayDefinition> predicates = new ArrayList<>();
        /**
         * 路由过滤器集合配置
         */
        private List<GatewayDefinition> filters = new ArrayList<>();
        /**
         * 路由规则转发的目标uri
         *
         * 建议lb协议<lb://serviceId>
         */
        @NotBlank(message = "uri不能为空")
        private String uri;
        /**
         * 路由执行顺序
         */
        private int order = 0;
    
        @Data
        public static class GatewayDefinition {
            //断言(过滤器)对应的Name
            private String name;
            //配置的断言(过滤器)规则
            private Map<String,String> args=new LinkedHashMap<>();
        }
    
        public RouteDefinition routeDefinition(){
            RouteDefinition routeDefinition=new RouteDefinition();
            routeDefinition.setId(serviceId);
            routeDefinition.setOrder(order);
            URI routeUri = !StringUtils.startsWith(uri,"lb")?UriComponentsBuilder.fromHttpUrl(uri).build().toUri():URI.create(uri);
            routeDefinition.setUri(routeUri);
            if(!CollectionUtils.isEmpty(filters)){
                routeDefinition.setFilters(filters.stream().map(f->{
                    FilterDefinition filterDefinition=new FilterDefinition();
                    filterDefinition.setName(f.name);
                    filterDefinition.setArgs(f.args);
                    return filterDefinition;
                }).collect(Collectors.toList()));
            }
            if(!CollectionUtils.isEmpty(predicates)){
                routeDefinition.setPredicates(predicates.stream().map(f->{
                    PredicateDefinition predicateDefinition=new PredicateDefinition();
                    predicateDefinition.setName(f.name);
                    predicateDefinition.setArgs(f.args);
                    return predicateDefinition;
                }).collect(Collectors.toList()));
            }
            return routeDefinition;
        }
    }
    

    3. SpringCloudGateway 请求到寻找路由的流程

    DispatcherHandler
    package org.springframework.web.reactive;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import org.springframework.beans.factory.BeanFactoryUtils;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.core.annotation.AnnotationAwareOrderComparator;
    import org.springframework.http.HttpStatus;
    import org.springframework.lang.Nullable;
    import org.springframework.web.server.ResponseStatusException;
    import org.springframework.web.server.ServerWebExchange;
    import org.springframework.web.server.WebHandler;
    import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
    
    /**
     * Central dispatcher for HTTP request handlers/controllers. Dispatches to
     * registered handlers for processing a request, providing convenient mapping
     * facilities.
     *
     * <p>{@code DispatcherHandler} discovers the delegate components it needs from
     * Spring configuration. It detects the following in the application context:
     * <ul>
     * <li>{@link HandlerMapping} -- map requests to handler objects
     * <li>{@link HandlerAdapter} -- for using any handler interface
     * <li>{@link HandlerResultHandler} -- process handler return values
     * </ul>
     *
     * <p>{@code DispatcherHandler} is also designed to be a Spring bean itself and
     * implements {@link ApplicationContextAware} for access to the context it runs
     * in. If {@code DispatcherHandler} is declared with the bean name "webHandler"
     * it is discovered by {@link WebHttpHandlerBuilder#applicationContext} which
     * creates a processing chain together with {@code WebFilter},
     * {@code WebExceptionHandler} and others.
     *
     * <p>A {@code DispatcherHandler} bean declaration is included in
     * {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux}
     * configuration.
     *
     * @author Rossen Stoyanchev
     * @author Sebastien Deleuze
     * @author Juergen Hoeller
     * @since 5.0
     * @see WebHttpHandlerBuilder#applicationContext(ApplicationContext)
     */
    public class DispatcherHandler implements WebHandler, ApplicationContextAware {
    
    	@Nullable
    	private List<HandlerMapping> handlerMappings;
    
    	@Nullable
    	private List<HandlerAdapter> handlerAdapters;
    
    	@Nullable
    	private List<HandlerResultHandler> resultHandlers;
    
    
    	/**
    	 * Create a new {@code DispatcherHandler} which needs to be configured with
    	 * an {@link ApplicationContext} through {@link #setApplicationContext}.
    	 */
    	public DispatcherHandler() {
    	}
    
    	/**
    	 * Create a new {@code DispatcherHandler} for the given {@link ApplicationContext}.
    	 * @param applicationContext the application context to find the handler beans in
    	 */
    	public DispatcherHandler(ApplicationContext applicationContext) {
    		initStrategies(applicationContext);
    	}
    
    
    	/**
    	 * Return all {@link HandlerMapping} beans detected by type in the
    	 * {@link #setApplicationContext injected context} and also
    	 * {@link AnnotationAwareOrderComparator#sort(List) sorted}.
    	 * <p><strong>Note:</strong> This method may return {@code null} if invoked
    	 * prior to {@link #setApplicationContext(ApplicationContext)}.
    	 * @return immutable list with the configured mappings or {@code null}
    	 */
    	@Nullable
    	public final List<HandlerMapping> getHandlerMappings() {
    		return this.handlerMappings;
    	}
    
    	@Override
    	public void setApplicationContext(ApplicationContext applicationContext) {
    		initStrategies(applicationContext);
    	}
    
        // 初始化处理
    	protected void initStrategies(ApplicationContext context) {
    		Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    				context, HandlerMapping.class, true, false);
    
    		ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
    		AnnotationAwareOrderComparator.sort(mappings);
    		this.handlerMappings = Collections.unmodifiableList(mappings);
    
    		Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    				context, HandlerAdapter.class, true, false);
    
    		this.handlerAdapters = new ArrayList<>(adapterBeans.values());
    		AnnotationAwareOrderComparator.sort(this.handlerAdapters);
    
    		Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    				context, HandlerResultHandler.class, true, false);
    
    		this.resultHandlers = new ArrayList<>(beans.values());
    		AnnotationAwareOrderComparator.sort(this.resultHandlers);
    	}
    
    
        // 获取映射处理器
    	@Override
    	public Mono<Void> handle(ServerWebExchange exchange) {
    		if (this.handlerMappings == null) {
    			return createNotFoundError();
    		}
    		return Flux.fromIterable(this.handlerMappings)
                     // 获取处理器,与已经注册好了的HandlerAdapter一一匹配
                     // org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler
                     //AbstractHandlerMapping 有多个子类,子类都会进入父类getHandler 
    				.concatMap(mapping -> mapping.getHandler(exchange))
    				.next()
    				.switchIfEmpty(createNotFoundError())
                      // 执行
    				.flatMap(handler -> invokeHandler(exchange, handler))
                      // 结果处理
    				.flatMap(result -> handleResult(exchange, result));
    	}
    
    	private <R> Mono<R> createNotFoundError() {
    		return Mono.defer(() -> {
    			Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND, "No matching handler");
    			return Mono.error(ex);
    		});
    	}
        // 看哪一种HandlerAdapter是支持该controller类型的
    	private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
    		if (this.handlerAdapters != null) {
    			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
    				if (handlerAdapter.supports(handler)) {
    					return handlerAdapter.handle(exchange, handler);
    				}
    			}
    		}
    		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
    	}
    
    	private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
    		return getResultHandler(result).handleResult(exchange, result)
    				.checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]")
    				.onErrorResume(ex ->
    						result.applyExceptionHandler(ex).flatMap(exResult -> {
    							String text = "Exception handler " + exResult.getHandler() +
    									", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
    							return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
    						}));
    	}
    
    	private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
    		if (this.resultHandlers != null) {
    			for (HandlerResultHandler resultHandler : this.resultHandlers) {
    				if (resultHandler.supports(handlerResult)) {
    					return resultHandler;
    				}
    			}
    		}
    		throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
    	}
    
    }
    
    

    其中 org.springframework.web.reactive.DispatcherHandler#handle(ServerWebExchange exchange)

    根据请求从handlerMappings获取对应的处理器映射,通过处理器映射,可以将web请求映射到正确的处理器(handler)上。

    @Override
    	public Mono<Object> getHandler(ServerWebExchange exchange) {
    		return getHandlerInternal(exchange).map(handler -> {
    			if (logger.isDebugEnabled()) {
    				logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
    			}
    			ServerHttpRequest request = exchange.getRequest();
    			if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
    				CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
    				CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
    				config = (config != null ? config.combine(handlerConfig) : handlerConfig);
    				if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
    					return REQUEST_HANDLED_HANDLER;
    				}
    			}
    			return handler;
    		});
    	}
    /**
    	 * Look up a handler for the given request, returning an empty {@code Mono}
    	 * if no specific one is found. This method is called by {@link #getHandler}.
    	 * <p>On CORS pre-flight requests this method should return a match not for
    	 * the pre-flight request but for the expected actual request based on the URL
    	 * path, the HTTP methods from the "Access-Control-Request-Method" header, and
    	 * the headers from the "Access-Control-Request-Headers" header.
    	 * @param exchange current exchange
    	 * @return {@code Mono} for the matching handler, if any
    	 */
    	protected abstract Mono<?> getHandlerInternal(ServerWebExchange exchange);
    

    在这里插入图片描述

    这里,看到了gateway的RoutePredicateHandlerMapping

    org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping

    RoutePredicateHandlerMapping

    org.springframework.cloud.gateway.config.GatewayAutoConfiguration 初始化

    package org.springframework.cloud.gateway.handler;
    
    import java.util.function.Function;
    
    import reactor.core.publisher.Mono;
    
    import org.springframework.cloud.gateway.config.GlobalCorsProperties;
    import org.springframework.cloud.gateway.route.Route;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.core.env.Environment;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.reactive.handler.AbstractHandlerMapping;
    import org.springframework.web.server.ServerWebExchange;
    
    import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT;
    import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DISABLED;
    import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.SAME;
    import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR;
    import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR;
    import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
    
    /**
     * @author Spencer Gibb
     */
    public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
    
       private final FilteringWebHandler webHandler;
       // 路由统一加载的实例(org.springframework.cloud.gateway.route.CompositeRouteLocator)
       // org.springframework.cloud.gateway.route.CachingRouteLocator
       private final RouteLocator routeLocator;
    
       private final Integer managementPort;
    
       private final ManagementPortType managementPortType;
    
       public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
             RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
             Environment environment) {
          this.webHandler = webHandler;
          this.routeLocator = routeLocator;
    
          this.managementPort = getPortProperty(environment, "management.server.");
          this.managementPortType = getManagementPortType(environment);
          setOrder(1);
          setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
       }
    
       private ManagementPortType getManagementPortType(Environment environment) {
          Integer serverPort = getPortProperty(environment, "server.");
          if (this.managementPort != null && this.managementPort < 0) {
             return DISABLED;
          }
          return ((this.managementPort == null
                || (serverPort == null && this.managementPort.equals(8080))
                || (this.managementPort != 0 && this.managementPort.equals(serverPort)))
                      ? SAME : DIFFERENT);
       }
    
       private static Integer getPortProperty(Environment environment, String prefix) {
          return environment.getProperty(prefix + "port", Integer.class);
       }
    
        // 网关路由时进入此方法
       @Override
       protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
          // don't handle requests on management port if set and different than server port
          if (this.managementPortType == DIFFERENT && this.managementPort != null
                && exchange.getRequest().getURI().getPort() == this.managementPort) {
             return Mono.empty();
          }
          exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
    
           // 获取配置路由
          return lookupRoute(exchange)
                // .log("route-predicate-handler-mapping", Level.FINER) //name this
                .flatMap((Function<Route, Mono<?>>) r -> {
                   exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
                   if (logger.isDebugEnabled()) {
                      logger.debug(
                            "Mapping [" + getExchangeDesc(exchange) + "] to " + r);
                   }
    
                   exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
                   return Mono.just(webHandler);
                }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                   exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
                   if (logger.isTraceEnabled()) {
                      logger.trace("No RouteDefinition found for ["
                            + getExchangeDesc(exchange) + "]");
                   }
                })));
       }
    
       @Override
       protected CorsConfiguration getCorsConfiguration(Object handler,
             ServerWebExchange exchange) {
          // TODO: support cors configuration via properties on a route see gh-229
          // see RequestMappingHandlerMapping.initCorsConfiguration()
          // also see
          // https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java
          return super.getCorsConfiguration(handler, exchange);
       }
    
       // TODO: get desc from factory?
       private String getExchangeDesc(ServerWebExchange exchange) {
          StringBuilder out = new StringBuilder();
          out.append("Exchange: ");
          out.append(exchange.getRequest().getMethod());
          out.append(" ");
          out.append(exchange.getRequest().getURI());
          return out.toString();
       }
    
       protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
           // 获取加载路由
          return this.routeLocator.getRoutes()
                // individually filter routes so that filterWhen error delaying is not a
                // problem
                .concatMap(route -> Mono.just(route).filterWhen(r -> {
                   // add the current route we are testing
                   exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                   return r.getPredicate().apply(exchange);
                })
                      // instead of immediately stopping main flux due to error, log and
                      // swallow it
                      .doOnError(e -> logger.error(
                            "Error applying predicate for route: " + route.getId(),
                            e))
                      .onErrorResume(e -> Mono.empty()))
                // .defaultIfEmpty() put a static Route not found
                // or .switchIfEmpty()
                // .switchIfEmpty(Mono.<Route>empty().log("noroute"))
                .next()
                // TODO: error handling
                .map(route -> {
                   if (logger.isDebugEnabled()) {
                      logger.debug("Route matched: " + route.getId());
                   }
                   validateRoute(route, exchange);
                   return route;
                });
    
          /*
           * TODO: trace logging if (logger.isTraceEnabled()) {
           * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
           */
       }
    
       /**
        * Validate the given handler against the current request.
        * <p>
        * The default implementation is empty. Can be overridden in subclasses, for example
        * to enforce specific preconditions expressed in URL mappings.
        * @param route the Route object to validate
        * @param exchange current exchange
        * @throws Exception if validation failed
        */
       @SuppressWarnings("UnusedParameters")
       protected void validateRoute(Route route, ServerWebExchange exchange) {
       }
    
       protected String getSimpleName() {
          return "RoutePredicateHandlerMapping";
       }
    
       public enum ManagementPortType {
    
          /**
           * The management port has been disabled.
           */
          DISABLED,
    
          /**
           * The management port is the same as the server port.
           */
          SAME,
    
          /**
           * The management port and server port are different.
           */
          DIFFERENT;
    
       }
    
    }
    
    RouteLocator路由加载
    package org.springframework.cloud.gateway.route;
    
    import reactor.core.publisher.Flux;
    /** 
     * org.springframework.cloud.gateway.route.CachingRouteLocator 缓存,有事件监听
     * org.springframework.cloud.gateway.route.CompositeRouteLocator 组合多种实现,提供统一入口
     * org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator 将路由定义信息转化为路由
     * @author Spencer Gibb
     */
    // TODO: rename to Routes?
    public interface RouteLocator {
    
       Flux<Route> getRoutes();
    
    }
    

    GatewayAutoConfiguration 加载代码

    @Bean
    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
          List<GatewayFilterFactory> gatewayFilters,
          List<RoutePredicateFactory> predicates,
          RouteDefinitionLocator routeDefinitionLocator,
          ConfigurationService configurationService) {
       return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
             gatewayFilters, properties, configurationService);
    }
    
    @Bean
    @Primary
    @ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
    // TODO: property to disable composite?
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
       return new CachingRouteLocator(
             new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
    }
    
    • RouteDefinitionRouteLocator
    package org.springframework.cloud.gateway.route;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import reactor.core.publisher.Flux;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.config.GatewayProperties;
    import org.springframework.cloud.gateway.event.FilterArgsEvent;
    import org.springframework.cloud.gateway.event.PredicateArgsEvent;
    import org.springframework.cloud.gateway.filter.FilterDefinition;
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
    import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
    import org.springframework.cloud.gateway.handler.AsyncPredicate;
    import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
    import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
    import org.springframework.cloud.gateway.support.ConfigurationService;
    import org.springframework.cloud.gateway.support.HasRouteId;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ApplicationEventPublisherAware;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.AnnotationAwareOrderComparator;
    import org.springframework.core.convert.ConversionService;
    import org.springframework.validation.Validator;
    import org.springframework.web.server.ServerWebExchange;
    
    /**
     * {@link RouteLocator} that loads routes from a {@link RouteDefinitionLocator}.
     *
     * @author Spencer Gibb
     */
    public class RouteDefinitionRouteLocator
    		implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
    
    	/**
    	 * Default filters name.
    	 */
    	public static final String DEFAULT_FILTERS = "defaultFilters";
    
    	protected final Log logger = LogFactory.getLog(getClass());
         // 路由定义信息
    	private final RouteDefinitionLocator routeDefinitionLocator;
    
    	private final ConfigurationService configurationService;
        // 路由RoutePredicate工厂,配置该路由决定采取哪种路由规则,如何配置前缀就可以找到对应的实例??
    	private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
        // 路由GatewayFilter工厂,配置该路由决定走哪些过滤器,如何配置前缀就可以找到对应的实例??
    	private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
    
    	private final GatewayProperties gatewayProperties;
    
    	@Deprecated
    	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
    			List<RoutePredicateFactory> predicates,
    			List<GatewayFilterFactory> gatewayFilterFactories,
    			GatewayProperties gatewayProperties, ConversionService conversionService) {
    		this.routeDefinitionLocator = routeDefinitionLocator;
    		this.configurationService = new ConfigurationService();
    		this.configurationService.setConversionService(conversionService);
    		initFactories(predicates);
    		gatewayFilterFactories.forEach(
    				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
    		this.gatewayProperties = gatewayProperties;
    	}
    
    	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
    			List<RoutePredicateFactory> predicates,
    			List<GatewayFilterFactory> gatewayFilterFactories,
    			GatewayProperties gatewayProperties,
    			ConfigurationService configurationService) {
    		this.routeDefinitionLocator = routeDefinitionLocator;
    		this.configurationService = configurationService;
            // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
    		initFactories(predicates);
            // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
    		gatewayFilterFactories.forEach(
    				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
    		this.gatewayProperties = gatewayProperties;
    	}
    
    	@Override
    	@Deprecated
    	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    		if (this.configurationService.getBeanFactory() == null) {
    			this.configurationService.setBeanFactory(beanFactory);
    		}
    	}
    
    	@Autowired
    	@Deprecated
    	public void setValidator(Validator validator) {
    		if (this.configurationService.getValidator() == null) {
    			this.configurationService.setValidator(validator);
    		}
    	}
    
    	@Override
    	@Deprecated
    	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
    		if (this.configurationService.getPublisher() == null) {
    			this.configurationService.setApplicationEventPublisher(publisher);
    		}
    	}
    
        // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
    	private void initFactories(List<RoutePredicateFactory> predicates) {
    		predicates.forEach(factory -> {
    			String key = factory.name();
    			if (this.predicates.containsKey(key)) {
    				this.logger.warn("A RoutePredicateFactory named " + key
    						+ " already exists, class: " + this.predicates.get(key)
    						+ ". It will be overwritten.");
    			}
    			this.predicates.put(key, factory);
    			if (logger.isInfoEnabled()) {
    				logger.info("Loaded RoutePredicateFactory [" + key + "]");
    			}
    		});
    	}
    
    	@Override
    	public Flux<Route> getRoutes() {
            // 将路由定义信息转化成路由信息
    		Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
    				.map(this::convertToRoute);
    
    		if (!gatewayProperties.isFailOnRouteDefinitionError()) {
    			// instead of letting error bubble up, continue
    			routes = routes.onErrorContinue((error, obj) -> {
    				if (logger.isWarnEnabled()) {
    					logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()
    							+ " will be ignored. Definition has invalid configs, "
    							+ error.getMessage());
    				}
    			});
    		}
    
    		return routes.map(route -> {
    			if (logger.isDebugEnabled()) {
    				logger.debug("RouteDefinition matched: " + route.getId());
    			}
    			return route;
    		});
    	}
         
        // 转换成路由信息
    	private Route convertToRoute(RouteDefinition routeDefinition) {
    		AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
    		List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
    
    		return Route.async(routeDefinition).asyncPredicate(predicate)
    				.replaceFilters(gatewayFilters).build();
    	}
    
    	@SuppressWarnings("unchecked")
        // 加载路由网关过滤器
    	List<GatewayFilter> loadGatewayFilters(String id,
    			List<FilterDefinition> filterDefinitions) {
    		ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
    		for (int i = 0; i < filterDefinitions.size(); i++) {
    			FilterDefinition definition = filterDefinitions.get(i);
                // 获取网关过滤器工厂
    			GatewayFilterFactory factory = this.gatewayFilterFactories
    					.get(definition.getName());
    			if (factory == null) {
    				throw new IllegalArgumentException(
    						"Unable to find GatewayFilterFactory with name "
    								+ definition.getName());
    			}
    			if (logger.isDebugEnabled()) {
    				logger.debug("RouteDefinition " + id + " applying filter "
    						+ definition.getArgs() + " to " + definition.getName());
    			}
    
    			// @formatter:off
                // 构造每个工厂里对应的config信息
    			Object configuration = this.configurationService.with(factory)
    					.name(definition.getName())
    					.properties(definition.getArgs())
    					.eventFunction((bound, properties) -> new FilterArgsEvent(
    							// TODO: why explicit cast needed or java compile fails
    							RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
    					.bind();
    			// @formatter:on
    
    			// some filters require routeId
    			// TODO: is there a better place to apply this?
    			if (configuration instanceof HasRouteId) {
    				HasRouteId hasRouteId = (HasRouteId) configuration;
    				hasRouteId.setRouteId(id);
    			}
                 // 获取过滤器是实例
    			GatewayFilter gatewayFilter = factory.apply(configuration);
    			if (gatewayFilter instanceof Ordered) {
    				ordered.add(gatewayFilter);
    			}
    			else {
    				ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
    			}
    		}
    
    		return ordered;
    	}
        // 获取过滤器,并根据ordered决定加载顺序
    	private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
    		List<GatewayFilter> filters = new ArrayList<>();
    
    		// TODO: support option to apply defaults after route specific filters?
    		if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
    			filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
    					new ArrayList<>(this.gatewayProperties.getDefaultFilters())));
    		}
    
    		if (!routeDefinition.getFilters().isEmpty()) {
    			filters.addAll(loadGatewayFilters(routeDefinition.getId(),
    					new ArrayList<>(routeDefinition.getFilters())));
    		}
    
    		AnnotationAwareOrderComparator.sort(filters);
    		return filters;
    	}
    
    	private AsyncPredicate<ServerWebExchange> combinePredicates(
    			RouteDefinition routeDefinition) {
    		List<PredicateDefinition> predicates = routeDefinition.getPredicates();
    		if (predicates == null || predicates.isEmpty()) {
    			// this is a very rare case, but possible, just match all
    			return AsyncPredicate.from(exchange -> true);
    		}
    		AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,
    				predicates.get(0));
    
    		for (PredicateDefinition andPredicate : predicates.subList(1,
    				predicates.size())) {
    			AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
    					andPredicate);
    			predicate = predicate.and(found);
    		}
    
    		return predicate;
    	}
        //加载断言
    	@SuppressWarnings("unchecked")
    	private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
    			PredicateDefinition predicate) {
            // 获取断言工厂
    		RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
    		if (factory == null) {
    			throw new IllegalArgumentException(
    					"Unable to find RoutePredicateFactory with name "
    							+ predicate.getName());
    		}
    		if (logger.isDebugEnabled()) {
    			logger.debug("RouteDefinition " + route.getId() + " applying "
    					+ predicate.getArgs() + " to " + predicate.getName());
    		}
    
    		// @formatter:off
    		Object config = this.configurationService.with(factory)
    				.name(predicate.getName())
    				.properties(predicate.getArgs())
    				.eventFunction((bound, properties) -> new PredicateArgsEvent(
    						RouteDefinitionRouteLocator.this, route.getId(), properties))
    				.bind();
    		// @formatter:on
             // 转换实例信息
    		return factory.applyAsync(config);
    	}
    
    }
    
    
    RouteDefinition路由定义

    SpringCloudGateway通过RouteDefinition来转换生成具体的路由信息。RouteDefinition的信息是怎么加载初始化到网关系统中的,主要是通过RouteDefinitionLocator(路由定义信息加载器)接口,实现RouteDefinition初始化加载

    • RouteDefinitionLocator源码
    /**
     * 路由定义信息的定位器,
     * 负责读取路由配置( org.springframework.cloud.gateway.route.RouteDefinition
     * 子类实现类
     *  1.CachingRouteDefinitionLocator -RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
     *  2.CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
     *  3.PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
     *  4.DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取RouteDefinition
     *  5.RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
     * @author Spencer Gibb
     */
    public interface RouteDefinitionLocator {
    
        /**
         * 获取RouteDefinition
         * @return
         */
        Flux<RouteDefinition> getRouteDefinitions();
    }
    

    RouteDefinitionLocator接口有且仅有一个方法getRouteDefinitions,此方法获取RouteDefinition的核心方法,返回Flux

    RouteDefinitionLocator 类图如下:

    graph TD
    RouteDefinitionLocator-->CachingRouteDefinitionLocator
    RouteDefinitionLocator-->CompositeRouteDefinitionLocator
    RouteDefinitionLocator-->PropertiesRouteDefinitionLocator
    RouteDefinitionLocator-->DiscoveryClientRouteDefinitionLocator
    RouteDefinitionLocator-->RouteDefinitionRepository
    

    子类功能描述:

    • CachingRouteDefinitionLocator:RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
    • CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
    • PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
    • RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
    • DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等
    • PropertiesRouteDefinitionLocator
    /**
     * 从Properties(GatewayProperties)中加载RouteDefinition信息
     * @author Spencer Gibb
     */
    public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
    
        /**
         * 从appliccation.yml中解析前缀为spring.cloud.gateway的配置
         */
        private final GatewayProperties properties;
    
        public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
            this.properties = properties;
        }
    
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
            return Flux.fromIterable(this.properties.getRoutes());
        }
    }
    

    PropertiesRouteDefinitionLocator很简单从GatewayProperties实例获取RouteDefinition信息

    • GatewayProperties 在GatewayProperties初始化加载文中已详细描述
    • Flux 响应式编程
    • CachingRouteDefinitionLocator
    /**
     * RouteDefinitionLocator 包装实现类,实现了路由定义的本地缓存功能
     * @author Spencer Gibb
     */
    public class CachingRouteDefinitionLocator implements RouteDefinitionLocator {
    
        /**
         * 实际路由定义定位器
         */
        private final RouteDefinitionLocator delegate;
        
        private final Flux<RouteDefinition> routeDefinitions;
        /**
         * 路由定义的本地缓存
         */
        private final Map<String, List> cache = new HashMap<>();
    
        public CachingRouteDefinitionLocator(RouteDefinitionLocator delegate) {
            this.delegate = delegate;
            routeDefinitions = CacheFlux.lookup(cache, "routeDefs", RouteDefinition.class)
                    .onCacheMissResume(() -> this.delegate.getRouteDefinitions());
    
        }
    
    }   
    

    RouteDefinitionLocator包装类,缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能

    • DiscoveryClientRouteDefinitionLocator
    public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
        /**
         * 注册中心客户端
         */
        private final DiscoveryClient discoveryClient;
        /**
         * 本地配置信息
         */
        private final DiscoveryLocatorProperties properties;
        /**
         * 路由ID前缀
         */
        private final String routeIdPrefix;
    
        public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
            this.discoveryClient = discoveryClient;
            this.properties = properties;
            if (StringUtils.hasText(properties.getRouteIdPrefix())) {
                this.routeIdPrefix = properties.getRouteIdPrefix();
            } else {
                this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
            }
        }
    
        /**
         * 通过注册中心查找服务组装路由定义信息
         * @return
         */
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
         ...代码在根据注册中心查找路由详细解析
    
        }
    }   
    

    DiscoveryClientRouteDefinitionLocator通过调用 DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组

    • CompositeRouteDefinitionLocator
    /**
     * 组合多个 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
     * @author Spencer Gibb
     */
    public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {
    
        /**
         * 所有路由定义定位器实例集合
         */
        private final Flux<RouteDefinitionLocator> delegates;
    
        public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
            this.delegates = delegates;
        }
    
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
            //将各个RouteDefinitionLocator的getRouteDefinitions合并返回统一的Flux<RouteDefinition>
            return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
        }
    }
    

    CompositeRouteDefinitionLocator 的主要作用就是将各个定位器合并提供统一的getRouteDefinitions方法入口

    通过子类实现具体功能可以很清晰的看到定位器加载RouteDefinition整个流程

    graph TD
    PropertiesRouteDefinitionLocator-->|配置文件加载初始化| CompositeRouteDefinitionLocator
    RouteDefinitionRepository-->|存储器中加载初始化| CompositeRouteDefinitionLocator
    DiscoveryClientRouteDefinitionLocator-->|注册中心加载初始化| CompositeRouteDefinitionLocator
    

    最终提供通过CompositeRouteDefinitionLocator提供统一的 getRouteDefinitions方法

    RouteDefinitionLocator实例的初始化在GatewayAutoConfiguration中已经完成

    • GatewayDiscoveryClientAutoConfiguration
    @Configuration
    @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
    @AutoConfigureBefore(GatewayAutoConfiguration.class)
    @ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
    @EnableConfigurationProperties
    public class GatewayDiscoveryClientAutoConfiguration {
    
        //初始化注册中心路由定义定位器
        @Bean
        @ConditionalOnBean(DiscoveryClient.class)
        @ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
        public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
                DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
            return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
        }
    
    • GatewayAutoConfiguration
       //初始化配置路由定义加载器
        @Bean
        @ConditionalOnMissingBean
        public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
            return new PropertiesRouteDefinitionLocator(properties);
        }
    
        //初始化存储路由定义加载器
        @Bean
        @ConditionalOnMissingBean(RouteDefinitionRepository.class)
        public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
            return new InMemoryRouteDefinitionRepository();
        }
    
         //初始化聚合路由定义加载器
        @Bean
        @Primary
        public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
            return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
        }
    

    在Spring-Cloud-Gateway初始化完成后需要的路由定义加载器已全部实例化完成,这样就为路由的加载创建完成了必要的条件。

    展开全文
  • 静态路由及默认路由——基本配置

    万次阅读 多人点赞 2019-05-11 11:51:22
    静态路由:是指用户或网络管理员手工配置的路由信息。当网络拓扑结构或链路状态发生改变时,需要网络管理员手工配置静态路由信息。 相比较动态路由协议,静态路由无需频繁的交换各自的路由表,配置简单,比较适合...

    原理简述:

    1。静态路由:是指用户或网络管理员手工配置的路由信息。当网络拓扑结构或链路状态发生改变时,需要网络管理员手工配置静态路由信息。

    相比较动态路由协议,静态路由无需频繁的交换各自的路由表,配置简单,比较适合小型、简单的网络环境。不适合大型和复杂的网络环境的原因是:当网络拓扑结构和链路状态发生改变时,网络管理员需要做大量的调整,工作量繁重,而且无法感知错误发生,不易排错。

    2。默认路由:是一种特殊的静态路由,当路由表中与数据包目的地址没有匹配的表项时,数据包将根据默认路由条目进行转发。默认路由在某些时候是非常有效的,例如在末梢网络中,默认路由可以大大简化路由器的配置,减轻网络管理员的工作负担。

    实验目的:

    (1)掌握静态路由(指定接口)的配置方法;

    (2)掌握静态路由(指定下一跳IP地址)的配置方法;

    (3)掌握静态路由连通性的测试方法;

    (4)掌握默认路由的配置方法;

    (5)掌握默认路由的测试方法;

    (6)掌握在简单网络中部署静态路由时的故障排除方法;

    (7)掌握简单的网络优化方法;

    实验内容:

    在三台路由器所组成的简单网络中,R1和R3各自连接着一个主机,现在要求通过配置基本的静态路由和默认路由来实现主机PC-1与PC-2之间的正常通信。

    实验拓扑:

    实验实现步骤:

    1。基础配置

    根据实验的要求进行相应的配置,使用ping命令检测各直连链路的连通性。

    在各直连链路间的IP连通性测试完之后,可以尝试在主机1上直接ping主机2。

    ???问题:为什么两个主机之间无法正常通信,是什么原因导致的?

    若假设主机1和主机2之间可以正常的通信,即可以正常的连通,则主机1将发送数据给其网关设备R1;而R1在收到其数据之后,根据数据包中的目的地址查看自己的路由表,找到相应的目的网络的所在的路由条目,并根据该条目中的下一跳和出接口信息将该数据转发给下一个路由器R2;同时R2采用相同的方式将数据转发给R3,最后R3页同样的将数据转发给与自己直接相连的主机2;主机2在收到数据后,与主机1发送数据到主机2的过程一样,再发送相应的回应信息给主机1。

    现在查看主机1与其网关设备R1间的连通性的状态:

    可以看出主机与网关之间的连通性正常,接下来检查网关设备与R1上的路由表:使用 display ip routing-table 命令。

    通过路由表上显示的信息,可以看到路由表上没有关于主机2所在网段的信息,同样可以使用相同的方法查看路由器R2和R3上的路由表信息。

    经过查看,可以看到:在路由器R2上没有关于主机1和主机2所在网段的信息,R3上没有关于主机1所在网段的信息。

    所以,以上的步骤验证了:在初始情况下各路由器的路由表上仅包含了与自己本身直接相连的网络的路由信息。

    因为现在的主机1和主机2之间跨越了若干个不同的网段,若要实现两者之间的通信,通过简单的IP地址等基础配置是不能实现的,需要在3台路由器上添加相应的路由信息,可以通过配置静态路由的方法来实现。

    2。实现主机1和主机2之间的通信:

    现在,在R1上配置目的网段为主机2所在网段的静态路由,即目的IP地址为192.168.20.0,掩码为255.255.255.0。相对应R1来讲,倘若要发送数据到主机2,则必须先发送给R2,所以R1的下一跳路由器是R2,R2与R1所在的直连链路上的物理端口S1/0/1接口 的IP地址即为下一跳IP地址,即10.0.12.2。

    [R1]ip route-static 192.168.20.0 255.255.255.0 10.0.12.2

    配置之后,查看R1的路由表:

    可以看出在路由器R1上已存在主机2所在网段的路由信息。

    接下来,采取同样的方式在R2上配置目的网段为主机2所在网段的静态路由,配置过后,查看其路由表。

    [R2]ip route-static 192.168.20.0 255.255.255.0 10.0.23.3
    
    [R2]dis ip routing-table 
    Route Flags: R - relay, D - download to fib
    ------------------------------------------------------------------------------
    Routing Tables: Public
             Destinations : 13       Routes : 13       
    
    Destination/Mask    Proto   Pre  Cost      Flags NextHop         Interface
    
          10.0.12.0/24  Direct  0    0           D   10.0.12.2       Serial1/0/1
          10.0.12.1/32  Direct  0    0           D   10.0.12.1       Serial1/0/1
          10.0.12.2/32  Direct  0    0           D   127.0.0.1       Serial1/0/1
        10.0.12.255/32  Direct  0    0           D   127.0.0.1       Serial1/0/1
          10.0.23.0/24  Direct  0    0           D   10.0.23.2       Serial1/0/0
          10.0.23.2/32  Direct  0    0           D   127.0.0.1       Serial1/0/0
          10.0.23.3/32  Direct  0    0           D   10.0.23.3       Serial1/0/0
        10.0.23.255/32  Direct  0    0           D   127.0.0.1       Serial1/0/0
          127.0.0.0/8   Direct  0    0           D   127.0.0.1       InLoopBack0
          127.0.0.1/32  Direct  0    0           D   127.0.0.1       InLoopBack0
    127.255.255.255/32  Direct  0    0           D   127.0.0.1       InLoopBack0
       192.168.20.0/24  Static  60   0          RD   10.0.23.3       Serial1/0/0  //已存在
    255.255.255.255/32  Direct  0    0           D   127.0.0.1       InLoopBack0
    

    此时,用主机1ping主机2,观察现象:

    发现,两台主机之间仍然无法正常互通。在主机1上的E0/0/1接口上进行数据抓包,观察现象:

    可以看到:此时主机1只发送了ICMP请求消息,而且也并没有得到任何的回应消息。

    原因:现在仅是实现主机1能够通过路由器将数据正常的转发给主机2,而主机2并没有实现,仍然是无法发送数据给主机1的。

    现在需要在R2和R3上的路由表中添加主机1所在网段的信息:

    在R3上配置目的网段为主机1所在网段的静态路由,目的IP地址为192.168.10.0,目的地址的掩码除了采用点分十进制的格式表示之外,还可以采用直接使用掩码长度的方式表示,即用24来表示相对应R3来讲,要发送数据到主机1上,首先发送给路由器R2,所以R3和R2所在直连链路上的物理接口S1/0/0即为数据转发口,也称为出接口,在配置中指定该接口即可。

    [R3]ip route-static 192.168.10.0 24 s1/0/1  //配置目的网段为主机1所在网段的静态路由
    
    [R2]ip route-static 192.168.10.0 24 s1/0/1  
    
    

    配置过后,查看各路由器的路由表信息:

    经过路由表的查看,你会看到每台路由器上都拥有了主机1和主机2所在网段的路由信息。再次在主机1上ping主机2,观察现象。

    3。实现全网全通来增强网络的可靠性

    按照上面的操作,现在已实现主机1和主机2之间的互通。若假设现在的网络出现了故障,主机1一侧的网络管理员发现无法正常的与主机2通信,于是先测试与网关设备R1和R3的连通性。

    可以看到:主机1无法与主机2的网关设备R3正常通信,所以此时网络管理员无法通过主机1登录到R3上进一步排查故障。

    现在的解决方法是:在R1的路由表中添加R2与R3间直连网段的路由信息,同样也在R3的路由表上添加R1与R2之间的直连链路的路由信息,已至实现全网的互通。

    配置之后,查看各路由器的路由表信息,查看内容;再由主机1ping主机2的网关设备R3。

    测试成功,主机1可以与R3正常通信,同样的主机2此时也可以与R1正常通信。

    4。使用默认路由实现简单的网络优化

    通过适当减少设备上的配置工作量,能够帮助网络管理员在进行故障排除时更轻松的排除故障,且相对较少的配置量也能减少在配置时出错的可能,另一方面,也能够相对减少对设备本身硬件的负担。

    现在,在R1上配置一条默认路由,即目的网段和掩码都是0,表示任何网络,下一跳为10.0.12.2,并删除先前配置的两条静态路由。

    [R1]ip route-static 0.0.0.0 0 10.0.12.2  //配置默认路由
    [R1]undo ip route-static 10.0.23.3 24 10.0.12.2   //删除静态路由
    [R1]undo ip route-static 192.168.20.0 24 10.0.12.2
    
    

    再次测试主机1与主机2之间的通信。

    该通信是正常的,证明了使用默认路由不但能够实现与静态路由同样的效果,还能减少配置量。同时在R3上也做相应的配置。

    [R3]ip route-static 0.0.0.0 0 s1/0/1  //配置默认路由
    [R3]undo ip route-static 10.0.12.0 24 s1/0/1
    [R3]undo ip route-static 192.168.10.0 24 10.0.23.2
    

    再次测试主机1与主机2之间的通信。

    可以看到主机1与主机2之间的通信正常。

    强调:在配置过程中,顺序是先配置默认路由,再删除原有的静态路由配置,这样的操作可以避免网络出现通信中断,即要在配置过程中注意操作的规范性和合理性。

    ???思考:在静态路由配置当中,可以采取指定下一跳IP地址的方式,也可以采取指定出接口的方式,这两种方式存在着什么区别?

    答:(1)在路由查找上:指定下一跳,会多进行一次路由的递归查找,拿下一跳去进行递归,得出出接口。

    (2)二层地址解析:指定下一跳使用最后一次递归的下一跳IP地址去解析下一跳二层地址。如果指定出接口的路由,数据包匹配到后直接用目的地址去解析下一跳地址。

     

     

    展开全文
  • 策略路由 路由策略 双点双向引入

    千次阅读 多人点赞 2020-07-10 01:33:17
    策略路由 路由策略 双点双向引入 一、策略路由 (一)策略路由–Policy-Based Routing—PBR 1、什么是策略路由: 对特定数据报文不按照路由表内的条目执行转发,根据需要按照某种策略改变数据报文转发路径。 2、...

    锲而不舍,金石可镂。

    策略路由 路由策略 双点双向引入

    一、策略路由

    (一)策略路由–Policy-Based Routing—PBR

    1、什么是策略路由:

    对特定数据报文不按照路由表内的条目执行转发,根据需要按照某种策略改变数据报文转发路径。

    2、运行机制:

    根据的报文的目的地址,报文的源地址,报文的大小和链路质量等属性制定策略路由,改变报文的转发路径。手动配置后基于策略转发,失败后再查找路由表转发。

    3、实现方式:

    华为设备支持3种策略路由:

    本地策略路由

    (1)名称:本地策略路由
    (2)对象:本设备产生流量
    (3)应用:对本机的ICMP,BGP等各种报文需要使用不同的源地址或者不同长度的报文通过不通方式进行发送时。

    接口策略路由

    (1)名称:接口策略路由
    (2)对象:流经本设备的数据
    (3)应用:针对用户不同源目地的数据按照流重定向选择下一跳,不按照路由表转发。

    智能策略路由(SSR)

    (1)名称:智能策略路由
    (2)对象:流经本设备的数据,基于链路质量信息为业务数据流选择最佳链路。
    (3)应用:对用户不同业务选择不同质量的链路。
    (4)注意:SSR的功能需要配合License来使用。

    (二)本地策略路由

    1、配置本地策略路由的匹配规则:

    可以通过ACL匹配到数据或者报文长度来进行对需要策略的数据执行匹配。

    2、配置本地策略路由的转发动作:

    可以通过接口或者下一跳地址发出。

    3、本地应用本地策略路由:

    在系统视图ip lcal policy-based-route X-X-----------调用名称为x-x的本地策略路由。

    (三)接口策略路由

    1、通过ACL匹配需要策略的流量

    2、定义流分类

    需要执行流策略的流量–即哪些流量需要转发
    通过ACL匹配需要策略的流量

    3、制定流行为

    指定需要执行流策略的动作,即如何转发

    4、制定流策略

    将流分类(匹配到需要转发的流量)和流行为(具体需要转发的动作)关联起来

    5、挂接流策略

    接口下在数据的进方向挂接流策略

    策略路由----PBR Policy Based Route—基于策略的路由(选址转发)

    策略路由----针对数据---------接口

    (四)策略路由配置

    1、策略路由指定的出接口要优于指定的下一跳
    2、策略路由指定的下一跳>路由表>策略部署的默认下一跳。

    二、路由策略

    路由策略----RP Route policy

    路由策略-------针对路由条目----路由协议----route policy
    人为的控制或者影响路由协议选路----过滤,cost,引入

    路由三要素----前缀----掩码----下一跳
    动态三要素----前缀----掩码----cost

    路由策略----路由条目

    对象:路由条目
    策略:过滤;修改路由属性

    1、路由匹配工具----抓取路由

    同意路由匹配工具

    ① ACL
    ② IP-preix----前缀列表
    ③ route-policy

    2、 BGP专属路由匹配工具

    ① ip murit-fiete----团体属性过滤列表
    ② ip as-patch-fiter----as路 径属性过滤列表

    3、路由策略工具----执行路由动作

    过滤

    ① route-policy
    ② fiter-policy

    属性修改

    route-policy

    2.1 前缀列表

    注意:由于route-policy不支持匹配Loopback接口,使用前缀列表来匹配loopbackO接口的路由。

    greater-equal X 掩码大约等于X
    less-equal X 掩码小于等于X

    如果只写前缀长度,掩码长度等于前缀长度
    如果只写greater-equal X,会自动补全less-equal 32

    在Route- policy同时调用ACL和ip-prix时,谁最后调用启用谁(ACL与ip-prix是覆盖关系)

    1、匹配任意掩码的路-------0.0.0.0 0 greater-equal x less-equal X
    2、匹配默认路----------------0.0.0.0 0 greater-equal 0 less-equal 0
    3、匹配所以明细路由-------0.0.0.0 0 greater-equal 1
    4、匹配所有的主机路-------0.0.0.0 0 greater-equal 32

    三、拓扑

    在这里插入图片描述

    四、策略配置

    AR-1的环回口loopback1 1.1.1.1/32模拟外部路由

    [AR-1]acl 2010
    [AR-1-acl-basic-2010] rule 5 permit source 1.1.1.1 0
    [AR-1-acl-basic-2010]rule 10 permit source 1.1.1.2 0
    
    [AR-1]route-policy di permit  node 10
    [AR-1-route-policy]if-match acl 2010
    
    [AR-1]ospf 
    [AR-1-ospf-1]import-route direct type 1 route-policy di
    

    4.1 网络互通

    在边界路由器完成双点双向路由引入实现全网互通与冗余备份

    [AR-3]isis 
    [AR-3-isis-1]network-entity 49.0001.0000.0000.0003.00
    [AR-3-isis-1]cost-style wide
    [AR-3-isis-1]quit
    [AR-3]int g0/0/0
    [AR-3-GigabitEthernet0/0/0]isis enable 
    [AR-3-GigabitEthernet0/0/0]int l0
    [AR-3-LoopBack0]isis enable 
    [AR-3-LoopBack0]quit
    [AR-3]ospf 1 router-id 3.3.3.3
    [AR-3-ospf-1]a 0   
    [AR-3-ospf-1-area-0.0.0.0]net 23.1.1.3 0.0.0.0、
    
    [AR-3]ospf 1	
    [AR-3-ospf-1]import-route isis
    [AR-3-ospf-1]isis 	
    [AR-3-isis-1]import-route ospf
    

    dis ip routing-table
    在这里插入图片描述

    4.2 网络优化

    通过路由策略消除存在次优路径与环路问题
    AR4:正常双向引入即可

    [AR-3]isis
    [AR-3-isis-1]undo import-route ospf
    [AR-3-isis-1]ospf 
    [AR-3-ospf-1]undo import-route  isis
    [AR-3-ospf-1]quit
    [AR-3]ospf 
    [AR-3-ospf-1]import-route  isis
    [AR-3-ospf-1]quit
    [AR-3]isis
    [AR-3-isis-1]import-route ospf
    [AR-3-isis-1]quit
    

    次优路径

    tracert 1.1.1.1
    在这里插入图片描述

    [AR-3]ospf 
    [AR-3-ospf-1]import-route  isis 1 type 1
    

    环路

    tracert 1.1.1.1
    在这里插入图片描述
    消除环路

    [AR-4]ip ip-prefix ospf index 10 permit 1.1.1.1 32
    [AR-4]ip ip-prefix ospf index 20 permit 2.2.2.2 32
    [AR-4]ip ip-prefix ospf index 30 permit 3.3.3.3 32
    [AR-4]ip ip-prefix ospf index 40 permit 4.4.4.4 32
    [AR-4]ip ip-prefix ospf index 50 permit 1.1.1.2 32
    
    [AR-4]route-policy ospf-->isis permit node 20
    [AR-4-route-policy]if-match  ip-prefix ospf
    [AR-4-route-policy]apply tag 100
    [AR-4-route-policy]quit
    [AR-4]isis	
    [AR-4-isis-1]import-route ospf 1 route-policy  ospf-->isis 
    [AR-4-isis-1]quit
    
    [AR-3]route-policy isis-->ospf deny node 10 //创建名称为isis-->ospf的路由策略组,此组的节点10执行拒绝路由的过滤动作
    [AR-3-route-policy]if-match tag 100         //此节点过滤带有100 tag标记的路由
    [AR-3-route-policy]quit
    [AR-3]route-policy isis-->ospf permit node 20
    
    [AR-3]ospf
    [AR-3-ospf-1]import-route isis route-policy  isis-->ospf  type 1 
    //在ospf进程中将isis进程1的路由导入,进入OSPF的IS-IS路由需要经过名称为isis-->ospf 的策略过滤 
    

    tracert 1.1.1.1
    在这里插入图片描述
    tracert 1.1.1.1
    在这里插入图片描述

    [AR-3]ip ip-prefix ospf index 10 permit 1.1.1.1 32
    [AR-3]ip ip-prefix ospf index 20 permit 2.2.2.2 32
    [AR-3]ip ip-prefix ospf index 30 permit 3.3.3.3 32
    [AR-3]ip ip-prefix ospf index 40 permit 4.4.4.4 32
    [AR-3]ip ip-prefix ospf index 50 permit 1.1.1.2 32
    
    [AR-3]route-policy ospf-->isis permit node 20
    [AR-3-route-policy]if-match ip-prefix ospf
    [AR-3-route-policy]apply  tag 200
    [AR-3-route-policy]isis
    [AR-3-isis-1]import-route ospf 1 route-policy  ospf-->isis 
    
    [AR-4]route-policy isis-->ospf deny node 8
    [AR-4-route-policy]if-match tag  200
    [AR-4-route-policy]quit
    [AR-4]route-policy isis-->ospf permit node 20
    
    [AR-4-ospf-1]import-route  isis route-policy  isis-->ospf  type 1
    

    tracert 1.1.1.1
    在这里插入图片描述
    tracert 1.1.1.1
    在这里插入图片描述

    [AR-4]route-policy isis-->ospf  permit node 15
    [AR-4-route-policy]apply tag 300
    [AR-4-route-policy]quit
    
    [AR-4]route-policy ospf-->isis  deny node 8
    [AR-4-route-policy]if-match  tag  400
    
    [AR-3]route-policy ospf-->isis  deny node 8
    [AR-3-route-policy]if-match tag  300
    [AR-3-route-policy]quit
    
    [AR-3]route-policy isis-->ospf  permit node 20
    [AR-3-route-policy]apply  tag 400
    

    消除次优

    [AR-4]route-policy isis-->pre permit node 20
    [AR-4-route-policy]if-match  tag  200
    [AR-4-route-policy]apply preference 151
    [AR-4-route-policy]quit
    [AR-4]isis
    [AR-4-isis-1]preference route-policy isis-->pre 15
    
    [AR-3]route-policy isis-->pre permit node 10
    [AR-3-route-policy]if-match tag  100
    [AR-3-route-policy]apply preference 151
    [AR-3-route-policy]isis 	
    [AR-3-isis-1]preference  route-policy  isis-->pre 15
    

    tracert 1.1.1.1
    在这里插入图片描述

    4.3 网络控制

    网络控制(不要修改接口开销)

    ① 修改开销(引入)
    ② 修改优先级(注意匹配策略)
    ③ 修改下一跳权值
    ④ 静态
    ⑤ 过滤

    (1)OSPF网络(AR-4除外)去往6.6.6.1的数据走上行线路:R3---->R5---->R6

    修改开销

    [AR-4]ip ip-prefix 35 permit  35.1.1.0 24
    [AR-4]ip ip-prefix 35 permit  6.6.6.1 32
    
    [AR-4]route-policy isis-->ospf permit  node 14
    [AR-4-route-policy]if-match ip-prefix 35 
    [AR-4-route-policy] apply cost 20 
    [AR-4-route-policy] apply tag 200
    

    在这里插入图片描述
    (2)OSPF网络(AR-3除外)去往6.6.6.2的数据走下行线路:R4---->R5---->R6

    修改优先级

    [AR-2]ip ip-prefix 23 permit 23.1.1.3 32
    [AR-2]ip ip-prefix 62 permit 6.6.6.2 32
    
    [AR-2]route-policy pre permit node 10
    [AR-2-route-policy]if-match ip-prefix 62
    [AR-2-route-policy]if-match  ip next-hop  ip-prefix 23
    [AR-2-route-policy]apply  preference 130
    [AR-2-route-policy]quit
    
    [AR-2]ospf	
    [AR-2-ospf-1]preference ase route-policy  pre
    

    dis ip routing-table
    在这里插入图片描述
    (3)IS-IS网络(AR-3除外)去往1.1.1.2的数据走下行线路: R4---->R2---->R1

    在AR-3上配置:增加1.1.1.2的开销值

    [AR-3]ip ip-prefix 452 permit 1.1.1.2 32
    [AR-3]route-policy ospf-->isis permit node 16
    	
    [AR-3-route-policy]if-match ip-prefix 452
    [AR-3-route-policy]apply tag 100
    [AR-3-route-policy]apply cost 200
    [AR-3-route-policy]quit
    
    [AR-3]route-policy ospf-->isis  permit  node 22
    [AR-3-route-policy]apply tag 100
    

    dis ip routing-table
    在这里插入图片描述
    (4)IS-IS网络(AR-4除外)去往1.1.1.1的数据走上行线路: R3---->R2---->R1

    策略路由----指定数据转发----不查看路由表

    ① 匹配数据
    acl

    ② 制定流分类
    traffic classifier

    ③ 制定流行为
    traffic behavior

    ④ 策略的组合
    traffic policy 数据与策略的组合

    ⑤ 挂接流策略
    在数据的进站方向挂接

    用策略路由写

    [AR-5]acl 3010
    [AR-5-acl-adv-3010]rule 10 permit ip source any destination 1.1.1.1 0  //匹配内网去往1.1.1.1的流量
    [AR-5-acl-adv-3010]quit
     
    [AR-5]traffic classifier host           //创建名称为host的流分类(这里匹配的到的数据将执行流动作)
    [AR-5-classifier-host]if-match acl 3010 //通过acl3010获得流量需要执行流分类	
    [AR-5-classifier-host]quit
    
    [AR-5]traffic behavior host                       //创建名称为host的流行为
    [AR-5-behavior-host]redirect ip-nexthop 35.1.1.3  //这个流行为匹配到的流量执行下一跳重定向动作
    [AR-5-behavior-host]quit
    
    [AR-5]traffic policy host                              //创建名称为host的流策略
    [AR-5-trafficpolicy-host]classifier host behavior host //将名称为host流分类匹配到数据和名称为host的流行为结合
    [AR-5-trafficpolicy-host]quit
    
    [AR-5]int g0/0/2  
    [AR-5-GigabitEthernet0/0/2]traffic-policy host  inbound
    //将名称为cl的流策略挂接到此接口的入方向,进入此接口被匹配到数据将安装流策略的规定动作转发,没有匹配到数据按照路由表正常转发
    

    策略优先级高于路由表优先级

    tracert 1.1.1.1
    在这里插入图片描述

    在这里插入图片描述

    本人所有文章都受版权保护,著作权归艺博东所有!未经授权,转载必究或附上其原创链接。

    展开全文
  • React中使用路由进行父子组件的通信

    万次阅读 2020-06-19 23:10:08
    最近我在学习 React.js 框架,在此记录一下我使用 react-router-dom 来实现单页应用(SPA)的路由跳转时,怎么处理父子组件间的通信。本文使用的是 HashRouter。 父组件中的路由配置 /** * 我使用了 react-router...

    最近我在学习 React.js 框架,在此记录一下我使用 react-router-dom 来实现单页应用(SPA)的路由跳转时,怎么处理父子组件间的通信。本文使用的是 HashRouter

    父组件中的路由配置

    /** 
     * 我使用了 react-router-dom 里面的 Switch 进行页面内的路由更新
     * NavPage 是父组件
     * Content 是子组件
     */
    
    class NavPage extends React.Component {
    	render () {
    		return (
    			<div className='body'>
    				<Switch>
    	  				<Route path='/navpage/content' component={Content} />
    				</Switch>
    			</div>
    		)
    	}
    }
    
    
    /**
     * 在父组件中定义一个方法,实现父组件跳转到子组件并传参数过去
     * 注意: 第一次用 push 方法,后面用 replace 方法
     * func 里面放置的是让子组件调用的时候可以回调告诉父组件的方法
     */
    
    navigateToSon () {
    	this.props.history.replace({pathname: '/navpage/content', data: {这里以对象的方式放置要传递的参数}, func: this.sonCallMe})
    }
    
    sonCallMe (args) {
    	console.log("My Son Call Me Now: ", args)	// 这里接收子组件传递过来的args,输出:"My Son Call Me Now: 我是你儿子"
    }
    
    

    子组件中的配置

    class Content extends React.Components {
    
      // 获取父组件 NavPage 初始化传过来的数据
      componentWillMount () {
        console.log(this.props.history.location.data)
      }
      componentWillReceiveProps () {
        console.log(this.props.history.location.data)
      }
    
      // 触发父组件传递过来的函数去与父组件通信
      callFather () {
          this.props.history.location.func("我是你儿子")
      } 
    
      render () {
    		return (
    			<div className='body'>
    				<div onClick={this.callFather.bind(this)}></div>
    			</div>
    		)
    	}
    
    }
    
    

    我是刚踏进 React.js 大门的小白,一路上踩了很多坑。希望可以帮助到跟我一样的小白们,有 React 方面的问题可以留言或者私信我们一起交流~

    展开全文
  • react做路由跳转,路由传参

    万次阅读 2019-06-30 20:37:30
    如果你项目当中用的是react全家桶,react + react-router + redux + axios + antd类似这样的组合的话那么做路由的话就是react-router, 首先要配置路由,关于react-router路由配置请看: ...而后可通过 this.p...
  • 静态路由 ISP路由 策略路由 OSPF路由

    千次阅读 2018-11-15 14:43:53
    静态路由(英语:Static routing),一种路由的方式,路由项(routing entry)由手动配置,而非动态决定。与动态路由不同,静态路由是固定的,不会改变,即使网络状况已经改变或是重新被组态。一般来说,静态路由是...
  • 华为 等价路由

    千次阅读 多人点赞 2020-05-14 23:16:57
    切忌自我感动,觉得自己有多努力多可怜,事实上,比你努力的人多的是,比你矫情的没几个。 文章目录 ...等价路由(ECMP)即为到达同一个目的 IP 或者目的网段存在多条 Cost 值相等的不同路由路径。
  • 整个动态路由的设置是我自己研究写的,现在项目中没发现什么问题。如发现有问题,欢迎前来纠正,谢谢!!! 链接:https://pan.baidu.com/s/1J9R2TkqJk0H9JMjqp2WcFw 提取码:n4rk 复制这段内容后打开百度网盘手机...
  • Django 路由

    万次阅读 2020-09-08 11:51:09
    文章目录Django 路由Django1.1.x 版本Django 2.2.x 之后的版本正则路径中的分组正则路径中的无名分组urls.pyviews.py正则路径中的有名分组urls.pyviews.py正则路径中的有名分组路由分发(include)反向解析普通路径...
  • linux 默认路由 主机路由 网络路由

    千次阅读 2018-12-18 10:17:48
    网关地址,”*” 表示目标是本主机所属的网络,不需要路由 Genmask 网络掩码 Flags 标记。一些可能的标记如下:   U — 路由是活动的   H — 目标是一个主机   G — 路由指向网关 ...
  • 路由策略 & 策略路由

    千次阅读 2019-08-29 11:45:43
    策略路由PBR(Policy-Based Routing)是一种依据用户制定的策略进行路由选择的机制,分为本地策略路由、接口策略路由和智能策略路由SPR(Smart Policy Routing)。 策略路由具有如下优点: 可以根据用户实际需求...
  • 静态路由和动态路由

    万次阅读 多人点赞 2018-12-23 16:50:31
    (2)掌握静态路由的配置; (3)掌握动态路由的配置。   实验要求: (1)写出静态路由的配置过程; (2)写出动态路由的配置过程。   一、路由器的...
  • vue-router(路由)详细教程

    万次阅读 多人点赞 2018-05-28 21:08:30
      由于Vue在开发时对路由支持的不足,于是官方补充了vue-router插件。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的...
  • 路由选择、路由协议与路由算法

    千次阅读 多人点赞 2017-05-20 15:52:43
    本文旨在区分清楚路由选择、路由协议和路由算法的关系。然后讲解常用路由协议和路由算法。什么是路由选择百科的说法: 路由选择是指选择通过互连网络从源节点向目的节点传输信息的通道,而且信息至少通过一个中间...
  • 一、路由 在Vue中 需要手动配置router路由规则 而Nuxt省去了手动挨个配置的麻烦 Nuxt会自动检测并配置路由 因此 只需要直接在浏览器访问即可 但Nuxt自动生成的路由规则有着一定的规律 普通路由 若组件是在文件夹里 ...
  • 静态路由和默认路由

    万次阅读 2018-03-16 14:08:21
    1静态路由和默认路由介绍:路由器在转发数据时,需要现在路由表中查找相应的路由,有三种途径(1)直连路由:路由器自动添加和自己直连的路由(2)静态路由:管理员手动添加的路由(3)动态路由:由路由协议动态建立...
  • angular9路由守卫使用

    万次阅读 2020-06-27 18:10:21
    三分钟上手路由守卫路由守卫是什么组件的创建守卫路由相关核心代码在路由中使用守卫参考资料 路由守卫是什么 任何用户都能在任何时候导航到任何地方。但有时候出于种种原因需要控制对该应用的不同部分的访问。可能...
  • 配置静态路由,动态路由,默认路由

    千次阅读 2019-07-30 16:06:09
    一、什么是路由 路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程[1]。路由工作在OSI参考模型第三层——网络层的数据包转发设备。路由器通过转发数据包来实现网络互连。虽然路由器可以支持...
  • windows如何添加静态路由

    万次阅读 2018-07-09 13:58:44
    一、静态路由含义说明 说明: 第一行表示: 所有到达192.168网段的都转送到192.268.242.65网关 第三行表示: 所有到达本机的数据包都被转送到x.x.213.1网关 第四行表示: 所有到达10.243网段的数据包都被...
  • 缺省路由(默认路由

    千次阅读 2019-10-09 15:29:18
    缺省路由属于特殊的静态路由 PC的网关其实就是一种缺省路由 缺省路由属于“替补路由”,只有当其他的路由不可达时才会使用缺省路由 缺省路由适用于边缘节点,以及企业出口 PC1(配置IP地址) IP地址:10.1.1.2 子网...
  • 路由策略和策略路由

    千次阅读 2018-10-16 11:21:54
    路由策略 1.什么是路由策略? 路由策略(Routing Policy)的作用是当路由器在发布、接收和引入路由信息时,可根据实际组网需要实施一些策略,以便对路由信息进行过滤或改变路由信息的属性,如: 控制路由的发布:...
  • React-router详细介绍及路由配置代码

    万次阅读 2019-06-05 21:06:16
    为了不进行后端路由,只进行前端路由 BrowserRouter --浏览器路由(属于后端路由) HasRouter --前端has路由(属于前端路由) 如何使用react-router? 一个单页应用一般只需要一个顶层的Router组件即可,不要再在...
  • 过滤路由:策略路由

    千次阅读 2018-06-05 15:14:38
    前言: 周一上课,没有好好听课,结果作业没完成,下课补作业!感觉喜欢自己学,不过老师也很厉害,要把我...3. 将R3上的eigrp路由重分布到OSPF路由中 4. 按照访问控制列表1往外分布eigrp路由 1. 在R4上查看...
  • 官方文档:... 路由的写法: 路由加载多个中间件: 给路由起个名字:index 路由重定向 控制器里实现重定向:路由外部重定向 路由内部重定向: (需重启项目,清理缓存) 路由分组和映射: ...
  • 一 ,缓存全部路由 在router-view外包裹keep-alive 例: <keep-alive> <router-view></router-view> </keep-alive> 二 ,指定路由缓存 使用 include <keep-alive include="该路由的...
  • Openwrt/Lede软路由设置为旁路由模式

    万次阅读 2020-04-30 17:17:20
    问题由来:我的软路由是放在客厅的,同时还兼NAS等功能,其它房间的网线均是从弱电箱牵过去的,且想把家里所有设备均设置在同一网段,但遗憾的是我的弱电箱到客厅只埋了1根网线,而弱电箱又是封闭的,散热差,只能...
  • 1.路由主要分为以下几点:(图见) 静态路由与动态路由的区别: 定义: 静态路由:静态路由是在路由器中设置固定的路由表;除非网络管理员进行干预,否则静态路由表不会发生变化。 动态路由:由网络中的路由器...
  • 路由设置

    千次阅读 2020-04-23 02:57:46
    路由设置: 设置路由可以访问内网数据库 [TOC] Microsoft Windows [版本 10.0.16299.1087] (c) 2017 Microsoft Corpora...
  • 静态路由介绍: 静态路由是指由用户或网络管理员手工配置的路由信息。当网络的拓扑结构或链路的状态发生变化时,网络管理员需要手工去修改路由表中相关的静态路由信息。静态路由信息在缺省情况下是私有的,不会传递...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 221,359
精华内容 88,543
关键字:

路由