欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

public interface RouteDefinitionRepository
		extends RouteDefinitionLocator, RouteDefinitionWriter {
}

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

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

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

而gateway中RouteDefinitionRepository接口的默認(rèn)的實(shí)現(xiàn)是InMemoryRouteDefinitionRepository,即在內(nèi)存中存儲(chǔ)路由配置,而且在 GatewayAutoConfiguration 配置中也激活了InMemoryRouteDefinitionRepository這個(gè)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 中可見(jiàn)存儲(chǔ)路由的是一個(gè)帶同步鎖的LinkedHashMap,而存儲(chǔ)刪除都是基于這個(gè)map對(duì)象操作。

3.動(dòng)態(tài)路由設(shè)計(jì)以及實(shí)現(xiàn)

  • 方案一:知道動(dòng)態(tài)路由的原理以后,我們可以基于redis設(shè)計(jì)一個(gè)InRedisRouteDefinitionRepository 實(shí)現(xiàn) RouteDefinitionRepository 接口即可,即網(wǎng)關(guān)部署多個(gè)也能動(dòng)態(tài)解決路由問(wèn)題
  • 方案二:可以基于nacos 配置動(dòng)態(tài)修改路由(理論上,待驗(yàn)證)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<>());
        }
    }

}

暫時(shí)在網(wǎng)關(guān)中提供接口實(shí)現(xiàn)路由的動(dòng)態(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;
    /**
     * 路由過(guò)濾器集合配置
     */

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

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

    /**
     * 斷言對(duì)應(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;
    /**
     * 對(duì)應(yīng)的路由規(guī)則
     */
    private Map<String, String> args = new LinkedHashMap<>();

}

業(yè)務(wù)層代碼 DynamicRouteService,最主要的是注入RouteDefinitionWriter 我們自己的實(shí)現(xiàn)類(lèi),替換默認(rè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) {
        // 判定當(dāng)前路由以及路徑是否存在
        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由于動(dòng)態(tài)路由引發(fā)不展示的問(wèn)題

聚合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.測(cè)試一下

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

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

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

6.寫(xiě)在最后

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

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

相關(guān)文章

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

    springboot處理url中帶斜杠/\字符的參數(shù)報(bào)400問(wèn)題

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

    解決Mybatis中mapper.xml文件update,delete及insert返回值問(wèn)題

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

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

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

    Spring框架對(duì)于Bean的管理詳解

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

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

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

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

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

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

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

    SpringBoot通過(guò)注解注入Bean的幾種方式解析

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

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

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

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

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

最新評(píng)論