亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringCloud GateWay動態(tài)路由用法

 更新時間:2024年10月31日 14:22:05   作者:Xiao_zuo_ya  
網(wǎng)關(guān)作為所有項目的入口,不希望重啟,因此動態(tài)路由是必須的,動態(tài)路由主要通過RouteDefinitionRepository接口實現(xiàn),其默認的實現(xiàn)是InMemoryRouteDefinitionRepository,即在內(nèi)存中存儲路由配置,可基于這個map對象操作,動態(tài)路由的實現(xiàn)方案有兩種

1.網(wǎng)關(guān)為什么需要動態(tài)路由?

網(wǎng)關(guān)的核心功能就是通過配置不同路由策略在配合注冊中心訪問不同的微服務(wù),而默認是在yaml文件中配置路由策略,而在項目上線后,網(wǎng)關(guān)作為所有項目的入口肯定不希望重啟,所以動態(tài)路由是必須的,我們在增加一個服務(wù),在不希望服務(wù)重新啟動的前提下能路由到該服務(wù),以及是基于代碼實現(xiàn)的網(wǎng)關(guān)動態(tài)路由

2.動態(tài)路由原理

public interface RouteDefinitionRepository
		extends RouteDefinitionLocator, RouteDefinitionWriter {
}

RouteDefinitionRepository是網(wǎng)關(guān)路由的存儲接口,RouteDefinitionLocator 是獲取存儲中的所有路由,RouteDefinitionWriter主要操作路由的存儲和刪除。

public interface RouteDefinitionLocator {
	Flux<RouteDefinition> getRouteDefinitions();

}
public interface RouteDefinitionWriter {
	Mono<Void> save(Mono<RouteDefinition> route);
	Mono<Void> delete(Mono<String> routeId);
}

而gateway中RouteDefinitionRepository接口的默認的實現(xiàn)是InMemoryRouteDefinitionRepository,即在內(nèi)存中存儲路由配置,而且在 GatewayAutoConfiguration 配置中也激活了InMemoryRouteDefinitionRepository這個Bean,代碼如下。

	@Bean
	@ConditionalOnMissingBean(RouteDefinitionRepository.class)
	public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
		return new InMemoryRouteDefinitionRepository();
	}
public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository {

	private final Map<String, RouteDefinition> routes = synchronizedMap(
			new LinkedHashMap<String, RouteDefinition>());

	@Override
	public Mono<Void> save(Mono<RouteDefinition> route) {
		return route.flatMap(r -> {
			routes.put(r.getId(), r);
			return Mono.empty();
		});
	}
	@Override
	public Mono<Void> delete(Mono<String> routeId) {
		return routeId.flatMap(id -> {
			if (routes.containsKey(id)) {
				routes.remove(id);
				return Mono.empty();
			}
			return Mono.defer(() -> Mono.error(
					new NotFoundException("RouteDefinition not found: " + routeId)));
		});
	}
	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return Flux.fromIterable(routes.values());
	}

}

InMemoryRouteDefinitionRepository 中可見存儲路由的是一個帶同步鎖的LinkedHashMap,而存儲刪除都是基于這個map對象操作。

3.動態(tài)路由設(shè)計以及實現(xiàn)

  • 方案一:知道動態(tài)路由的原理以后,我們可以基于redis設(shè)計一個InRedisRouteDefinitionRepository 實現(xiàn) RouteDefinitionRepository 接口即可,即網(wǎng)關(guān)部署多個也能動態(tài)解決路由問題
  • 方案二:可以基于nacos 配置動態(tài)修改路由(理論上,待驗證)nacos的配置也是可以熱加載的。
@Slf4j
@Configuration("redisRouteDefinition")
@AllArgsConstructor
public class InRedisRouteDefinitionRepository implements RouteDefinitionRepository {

    private RedisTemplate redisTemplate;

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {

        return route.flatMap(r -> {
            redisTemplate.opsForHash().put(DynamicRouterConstants.DYNAMIC_ROUTER_KEY_CONFIG, r.getId(), new Gson().toJson(r));
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            Object router = redisTemplate.opsForHash().get(DynamicRouterConstants.DYNAMIC_ROUTER_KEY_CONFIG, id);
            if (!Objects.isNull(router)) {
                redisTemplate.opsForHash().delete(DynamicRouterConstants.DYNAMIC_ROUTER_KEY_CONFIG, id);
                return Mono.empty();
            }
            return Mono.defer(() -> Mono.error(
                new NotFoundException("RouteDefinition not found: " + routeId)));
        });
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<String> values = redisTemplate.opsForHash().values(DynamicRouterConstants.DYNAMIC_ROUTER_KEY_CONFIG);
        if (CollUtil.isNotEmpty(values)) {
            List<RouteDefinition> definitions = values.stream()
                .map(s -> new Gson().fromJson(s, RouteDefinition.class))
                .collect(Collectors.toList());
            return Flux.fromIterable(definitions);
        } else {
            return Flux.fromIterable(new ArrayList<>());
        }
    }

}

暫時在網(wǎng)關(guān)中提供接口實現(xiàn)路由的動態(tài)增加和修改Controller

@RestController
@RequestMapping("/route")
@AllArgsConstructor
public class RouteController {

    private DynamicRouteService dynamicRouteService;

    @PostMapping
    public void saveRouteDefinition(@RequestBody GatewayRouteDefinition routeDefinition) {
        dynamicRouteService.saveRouteDefinition(routeDefinition);
    }

    @DeleteMapping("/{id}")
    public void deleteRouteDefinition(@PathVariable String id) {
        dynamicRouteService.deleteRouteDefinition(id);
    }

    @PutMapping
    public void update(@RequestBody GatewayRouteDefinition routeDefinition) {
        dynamicRouteService.updateRouteDefinition(routeDefinition);
    }

    @GetMapping
    public IPage<RouterConfig> getRouterConfigByPage(RouterConfigQueryParams params) {
        return dynamicRouteService.getRouterConfigByPage(params);
    }

}

路由參數(shù)

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class GatewayRouteDefinition {

    /**
     * 路由的Id
     */
    private String id;
    /**
     * 路由斷言集合配置
     */

    private List<GatewayPredicateDefinition> predicates;
    /**
     * 路由過濾器集合配置
     */

    private List<GatewayFilterDefinition> filters;
    /**
     * 路由規(guī)則轉(zhuǎn)發(fā)的目標uri
     */
    private String uri;

    /**
     * 路由執(zhí)行的順序
     */
    private int order;
}
@Data
public class GatewayPredicateDefinition implements Serializable {

    /**
     * 斷言對應(yīng)的Name
     */
    private String name;

    /**
     * 配置的斷言規(guī)則
     */
    private Map<String, String> args = new LinkedHashMap<>();

}
@Data
public class GatewayFilterDefinition implements Serializable {

    /**
     * Filter Name
     */
    private String name;
    /**
     * 對應(yīng)的路由規(guī)則
     */
    private Map<String, String> args = new LinkedHashMap<>();

}

業(yè)務(wù)層代碼 DynamicRouteService,最主要的是注入RouteDefinitionWriter 我們自己的實現(xiàn)類,替換默認的配置

@Service
public class DynamicRouteServiceImpl implements DynamicRouteService {

    @Resource(name = "redisRouteDefinition")
    private RouteDefinitionWriter routeDefinitionWriter;

    @Autowired
    private IRouterConfigService routerConfigService;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void saveRouteDefinition(GatewayRouteDefinition definition) {
        // 判定當前路由以及路徑是否存在
        LambdaQueryWrapper<RouterConfig> wrapper = Wrappers.<RouterConfig>lambdaQuery()
            .eq(RouterConfig::getRouterName, definition.getId())
            .eq(RouterConfig::getRouterPath, definition.getUri());
        List<RouterConfig> list = routerConfigService.list(wrapper);
        BizVerify.verify(CollUtil.isEmpty(list), "路由已經(jīng)存在");
        routerConfigService.save(paramsConvert(definition));
        RouteDefinition routerDefinition = DynamicRouteUtils.convertToRouteDefinition(definition);
        routeDefinitionWriter.save(Mono.just(routerDefinition)).subscribe();
    }

    @Override
    public void updateRouteDefinition(GatewayRouteDefinition routeDefinition) {
        routerConfigService.updateById(paramsConvert(routeDefinition));
        RouteDefinition definition = DynamicRouteUtils.convertToRouteDefinition(routeDefinition);
        deleteRouteDefinition(definition.getId());
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
    }

    @Override
    public void deleteRouteDefinition(String routerId) {
        routerConfigService.removeById(routerId);
        routeDefinitionWriter
            .delete(Mono.just(routerId))
            .then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
            .onErrorResume((t) -> t instanceof NotFoundException, (t) -> Mono.just(ResponseEntity.notFound().build()));
    }


    private RouterConfig paramsConvert(GatewayRouteDefinition routeDefinition) {
        String filterJson = null;
        String PredicatesJson = null;
        try {
            filterJson = objectMapper.writeValueAsString(routeDefinition.getFilters());
            PredicatesJson = objectMapper.writeValueAsString(routeDefinition.getPredicates());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return new RouterConfig()
            .setRouterName(routeDefinition.getId())
            .setRouterPath(routeDefinition.getUri())
            .setRouterOrder(routeDefinition.getOrder())
            .setRouterFilters(filterJson)
            .setRouterPredicates(PredicatesJson);
    }

    @Override
    public IPage<RouterConfig> getRouterConfigByPage(RouterConfigQueryParams params) {
        LambdaQueryWrapper<RouterConfig> wrapper = Wrappers.<RouterConfig>lambdaQuery()
            .like(StrUtil.isNotEmpty(params.getRouterName()), RouterConfig::getRouterName, params.getRouterName());
        return routerConfigService.page(new Page<>(params.getPageNum(), params.getPageSize()), wrapper);
    }
}

4.網(wǎng)關(guān)中聚合swagger由于動態(tài)路由引發(fā)不展示的問題

聚合swagger聚合核心代碼

package com.kill.core.provider;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.List;

/**
 * <pre>
 * +--------+---------+-----------+---------+
 * |                                        |
 * +--------+---------+-----------+---------+
 * </pre>
 *
 * @author wangjian
 * @since 1019/11/01 11:58:32
 */
@Component
@Primary
@AllArgsConstructor
public class SwaggerResourceProvider implements SwaggerResourcesProvider {

    private static final String SWAGGER2URL = "/v2/api-docs";

    private RouteDefinitionRepository repository;

    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        repository.getRouteDefinitions().subscribe(
            route -> {
                if (CollUtil.isNotEmpty(route.getPredicates())) {
                    route.getPredicates().forEach(
                        predicateDefinition -> {
                            if (CollUtil.isNotEmpty(predicateDefinition.getArgs())) {
                                if (StrUtil.isNotEmpty(predicateDefinition.getArgs().get("pattern"))) {
                                    resources.add(
                                        swaggerResource(route.getId(),
                                            predicateDefinition.getArgs().get("pattern").replace("/**", SWAGGER2URL)));
                                }
                                if (StrUtil.isNotEmpty(predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0"))) {
                                    resources.add(
                                        swaggerResource(route.getId(),
                                            predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)));
                                }
                            }

                        });
                }
            });
        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }

}

5.測試一下

swagger中目前只有這一個路由,調(diào)用路由新增一個

再次刷新swagger,OK 已經(jīng)看到新的路由了

redis中也已經(jīng)看到了路由的配置

6.寫在最后

不可能所有的代碼拿過來就能用,每個人的理解也不盡相同,記錄在這里希望能提供一個思路,能解決到自己遇到的問題,而不是希望大家看到后,說拷貝過來的東西都是垃圾,你可以看,如果沒有幫助到你我也很遺憾。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot處理url中帶斜杠/\字符的參數(shù)報400問題

    springboot處理url中帶斜杠/\字符的參數(shù)報400問題

    這篇文章主要介紹了springboot處理url中帶斜杠/\字符的參數(shù)報400問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 解決Mybatis中mapper.xml文件update,delete及insert返回值問題

    解決Mybatis中mapper.xml文件update,delete及insert返回值問題

    這篇文章主要介紹了解決Mybatis中mapper.xml文件update,delete及insert返回值問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 詳解Spring boot+CXF開發(fā)WebService Demo

    詳解Spring boot+CXF開發(fā)WebService Demo

    這篇文章主要介紹了詳解Spring boot+CXF開發(fā)WebService Demo,非常具有實用價值,需要的朋友可以參考下
    2017-05-05
  • Spring框架對于Bean的管理詳解

    Spring框架對于Bean的管理詳解

    在實際開發(fā)中,我們往往要用到Spring容器為我們提供的諸多資源,例如想要獲取到容器中的配置、獲取到容器中的Bean等等。本文為大家詳細講講工具類如何獲取到Spring容器中的Bean,需要的可以參考一下
    2022-07-07
  • jsoup?框架的使用小結(jié)

    jsoup?框架的使用小結(jié)

    jsoup 是一款基于Java的HTML解析器,它提供了一套非常省力的API,不但能直接解析某個URL地址、HTML文本內(nèi)容,而且還能通過類似于 DOM、CSS 或者jQuery的方法來操作數(shù)據(jù),所以jsoup也可以被當做爬蟲工具使用,這篇文章主要介紹了jsoup使用,需要的朋友可以參考下
    2023-04-04
  • SpringMVC中日期格式的轉(zhuǎn)換

    SpringMVC中日期格式的轉(zhuǎn)換

    本文主要介紹了SpringMVC中日期格式轉(zhuǎn)換的相關(guān)知識:用來解決日期提交轉(zhuǎn)換異常的問題。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • Java實現(xiàn)斗地主案例

    Java實現(xiàn)斗地主案例

    這篇文章主要為大家詳細介紹了Java實現(xiàn)斗地主案例,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • SpringBoot通過注解注入Bean的幾種方式解析

    SpringBoot通過注解注入Bean的幾種方式解析

    這篇文章主要為大家介紹了SpringBoot注入Bean的幾種方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-03-03
  • Spring @Bean注解配置及使用方法解析

    Spring @Bean注解配置及使用方法解析

    這篇文章主要介紹了Spring @Bean注解配置及使用方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • SpringBoot基于過濾器和內(nèi)存實現(xiàn)重復(fù)請求攔截功能

    SpringBoot基于過濾器和內(nèi)存實現(xiàn)重復(fù)請求攔截功能

    這篇文章主要介紹了SpringBoot基于過濾器和內(nèi)存實現(xiàn)重復(fù)請求攔截,這里我們使用過濾器的方式對進入服務(wù)器的請求進行過濾操作,實現(xiàn)對相同客戶端請求同一個接口的過濾,需要的朋友可以參考下
    2023-01-01

最新評論