В этой статье будет реализована более глубокая реализация динамической маршрутизации.Идеи реализации следующие:
- 1. Создайте проект обслуживания информации о маршрутизации (динамический маршрут), чтобы реализовать добавление, удаление, изменение и запрос информации о маршрутизации в mysql.
- 2. Обеспечьте функцию публикации.После публикации информация о маршрутизации и информация о версии сохраняются в Redis, а остальной интерфейс предоставляется извне для получения информации о маршрутизации.
- 3. Шлюз (шлюз-динамический-маршрут) запускает запланированную задачу, регулярно извлекает последнюю версию информации о маршрутизации, опубликованную в остальном интерфейсе, и сравнивает номера версий.Если номер версии шлюза не соответствует номеру версии в Остальной интерфейс, получить информацию о маршрутизации и обновить ее.
- 4. Общая архитектура разработана следующим образом:
Согласно вышеизложенным идеям реализуется код, ниже будут созданы два проекта, которые необходимо зарегистрировать на eureka.
- динамический маршрут, проект маршрутизации
- шлюз-динамический-маршрут, шлюз, информация о маршрутизации не настроена по умолчанию (не перенаправляется в службу-потребитель)
- потребительская служба, потребительская служба, перенаправляет запросы в эту службу после настройки динамической маршрутизации.
2. Создайте динамический маршрут проекта обслуживания информации о маршрутизации, чтобы реализовать функции добавления, удаления, изменения, запроса и публикации информации о маршрутах. Информация сохраняется в mysql, а затем после публикации сохраняется в Redis. Когда данные маршрутизации предоставляются извне, информация о маршрутизации в Redis возвращается (используя Cache для ответа на запросы чтения задачи синхронизации шлюза)
- Есть две таблицы, таблица информации о маршрутизации и таблица выпуска версии.Структура таблицы следующая:
- Реализация добавления, удаления, изменения и проверки не расширяется по одной из-за нехватки места.Вы можете просмотреть код проекта, который был загружен в облако кода.Следующие страницы размещены на проекте.Страницы относительно просто.
Ниже приводится информация о версии и информация о маршрутизации, возвращаемая оставшимся интерфейсом.Сначала шлюз получает номер версии и сравнивает его с локальным номером версии.Если он несовместим, информация о маршрутизации вытягивается через этот интерфейс.
Получить поддерживаемую информацию о маршрутизации
3. Основное внимание уделяется проекту шлюза, создайте проект динамического маршрута шлюза, установите номер версии по умолчанию равным 0 при запуске шлюза, извлекайте проект удаленной маршрутизации каждые 60 секунд через запланированное задание, чтобы предоставить номер последней версии, и сравните с номером версии шлюза. Если он несовместим, извлеките последнюю информацию о маршрутизации проекта удаленной маршрутизации, обновите ее до маршрутизации шлюза и в то же время перезапишите номер локальной версии последним номером версии.
Из-за большого количества кода блог в основном делится идеями реализации и публикует ключевой код, который был отправлен в облако кода, вы можете скачать проект, чтобы просмотреть весь код.
- 1. Запустите запланированное задание, зарегистрируйтесь в erueka, добавьте RestTemplate Bean и получите доступ к проекту маршрутизации в виде балансировки нагрузки.
@EnableScheduling
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayDynamicRouteApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayDynamicRouteApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
- 2. Класс реализации запланированной задачи
/**
* 定时任务,拉取路由信息
* 路由信息由路由项目单独维护
*/
@Component
public class DynamicRouteScheduling {
@Autowired private RestTemplate restTemplate;
@Autowired private DynamicRouteService dynamicRouteService;//动态路由实现类,与前篇博客中的实现类代码是一样的
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final String dynamicRouteServerName = "dynamic-route-service";
//发布路由信息的版本号
private static Long versionId = 0L;
//每60秒中执行一次
//如果版本号不相等则获取最新路由信息并更新网关路由
@Scheduled(cron = "*/60 * * * * ?")
public void getDynamicRouteInfo(){
try{
System.out.println("拉取时间:" + dateFormat.format(new Date()));
//先拉取版本信息,如果版本号不想等则更新路由
Long resultVersionId = restTemplate.getForObject("http://"+ dynamicRouteServerName +"/version/lastVersion" , Long.class);
System.out.println("路由版本信息:本地版本号:" + versionId + ",远程版本号:" + resultVersionId);
if(resultVersionId != null && versionId != resultVersionId){
System.out.println("开始拉取路由信息......");
String resultRoutes = restTemplate.getForObject("http://"+ dynamicRouteServerName +"/gateway-routes/routes" , String.class);
System.out.println("路由信息为:" + resultRoutes);
if(!StringUtils.isEmpty(resultRoutes)){
List<GatewayRouteDefinition> list = JSON.parseArray(resultRoutes , GatewayRouteDefinition.class);
for(GatewayRouteDefinition definition : list){
//更新路由
RouteDefinition routeDefinition = assembleRouteDefinition(definition);
dynamicRouteService.update(routeDefinition);
}
versionId = resultVersionId;
}
}
}catch (Exception e){
e.printStackTrace();
}
}
//把前端传递的参数转换成路由对象
private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gwdefinition) {
RouteDefinition definition = new RouteDefinition();
definition.setId(gwdefinition.getId());
definition.setOrder(gwdefinition.getOrder());
//设置断言
List<PredicateDefinition> pdList=new ArrayList<>();
List<GatewayPredicateDefinition> gatewayPredicateDefinitionList=gwdefinition.getPredicates();
for (GatewayPredicateDefinition gpDefinition: gatewayPredicateDefinitionList) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setArgs(gpDefinition.getArgs());
predicate.setName(gpDefinition.getName());
pdList.add(predicate);
}
definition.setPredicates(pdList);
//设置过滤器
List<FilterDefinition> filters = new ArrayList();
List<GatewayFilterDefinition> gatewayFilters = gwdefinition.getFilters();
for(GatewayFilterDefinition filterDefinition : gatewayFilters){
FilterDefinition filter = new FilterDefinition();
filter.setName(filterDefinition.getName());
filter.setArgs(filterDefinition.getArgs());
filters.add(filter);
}
definition.setFilters(filters);
URI uri = null;
if(gwdefinition.getUri().startsWith("http")){
uri = UriComponentsBuilder.fromHttpUrl(gwdefinition.getUri()).build().toUri();
}else{
uri = URI.create(gwdefinition.getUri());
}
definition.setUri(uri);
return definition;
}
}
- 3. Шлюз предоставляет контроллер, который получает всю информацию о маршрутизации.
/**
* 查询网关的路由信息
*/
@RestController
@RequestMapping("/route")
public class DynamicRouteController {
@Autowired private RouteDefinitionLocator routeDefinitionLocator;
//获取网关所有的路由信息
@RequestMapping("/routes")
public Flux<RouteDefinition> getRouteDefinitions(){
return routeDefinitionLocator.getRouteDefinitions();
}
}
4. Запустите eureka, dynamic-route, gateway-dynamic-route, Consumer-Service.
5. Добавьте новую часть информации о маршрутизации через проект динамического маршрута, uri маршрута — потребительская служба, и маршрут будет опубликован.
При публикации маршрута в Redis будут добавлены номер последней версии и информация о маршрутизации из таблицы версий. На следующем рисунке показана информация о маршрутизации, сохраненная в Redis. Шлюз регулярно сначала получает информацию о версии и информацию о маршрутизации из Redis.6. Поскольку шлюз не настроен с информацией о маршрутизации, вся информация о маршрутизации может быть получена через localhost: 9999/route/routes, В настоящее время существует две информации о маршрутизации, которые являются информацией о маршрутизации по умолчанию, извлеченной из eureka шлюзом. , а не сконфигурированная информация о маршрутизации.
7. Подождав 60 секунд, шлюз извлекает номер последней версии проекта динамического маршрута через RestTemplate. Если обнаруживается несоответствие, он извлекает последнюю информацию о маршрутизации и обновляет ее до маршрутизации шлюза.
8. Получите доступ к сервису-потребителю через шлюз, убедитесь, что информация о маршрутизации обновлена для шлюза, и посетите:http://localhost:9999/zy/hello?name=zy
9. Снова проверьте всю информацию о маршрутизации, вы можете видеть, что потребительская служба была настроена на маршрутизацию шлюза.
10. Повторно сравнивайте номера версий каждые 60 секунд. При выпуске нового номера версии будет извлечена сохраненная информация о маршрутизации. В противном случае шлюз не будет обновлять маршрут.
11. Измените информацию о маршрутизации, измените утверждение Path=/zy/** на Path=/consumer/** и опубликуйте его. Через 60 секунд консоль шлюза получит последнюю информацию о маршрутизации.
посетить в это времяhttp://localhost:9999/zy/hello?name=zyСообщается об ошибке, поскольку путь утверждения маршрута был изменен, и маршрут недоступен.
нужно пройтиhttp://localhost:9999/consumer/hello?name=zyдоступ, возврат в обычном режиме
Ну вот и закончена продвинутая реализация динамической маршрутизации.Из-за нехватки места все коды не выложены.Блог в основном знакомит с идеями реализации динамической маршрутизации.Код можно реализовать по своим привычкам.
Код загружен в облако кода:
- eureka-server
- dynamic-route, в оформлении есть таблица sql
- gateway-dynamic-route
- consumer-service
Информация о версии проекта выглядит следующим образом:
- SpringBoot 2.0.6.RELEASE
- SpringCloud Finchley.SR2
Реализовать публикацию в оттенках серого
Добавьте 2 маршрутные данные, тот же «шаблон»: «/cm1/**», укажите на разные сервисы, доступ
http://localhost:9999/cm1/hello?name=alex
Страница появляется случайным образом: hello alexfrom default, hello alexfrom b, указывая на то, что при балансировке нагрузки осуществляется доступ к двум службам, а вес можно регулировать, регулируя вес.
Ссылка на эту статью:blog.CSDN.net/Тема 199110…
yml в json
- id: admin-service
uri: lb://admin-service
predicates:
- Path=/admin/**
- Weight=service1, 90
filters:
- SwaggerHeaderFilter
- StripPrefix=1
- id: order-service
uri: lb://order-service
predicates:
- Path=/order-s/**
filters:
- SwaggerHeaderFilter
- StripPrefix=1
- id: test-service
uri: lb://test
predicates:
- Path=/demo/**
filters:
- SwaggerHeaderFilter
- StripPrefix=1
[
{
"route_id": "admin-service",
"route_definition": {
"id": "admin-service",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/admin/**"
}
},
{
"name": "Weight",
"args": {
"_genkey_0": "service1",
"_genkey_1": "90"
}
}
],
"filters": [
{
"name": "SwaggerHeaderFilter",
"args": {}
},
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"uri": "lb://admin-service",
"order": 0
},
"order": 0
},
{
"route_id": "order-service",
"route_definition": {
"id": "order-service",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/order-s/**"
}
}
],
"filters": [
{
"name": "SwaggerHeaderFilter",
"args": {}
},
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"uri": "lb://order-service",
"order": 0
},
"order": 0
},
{
"route_id": "test-service",
"route_definition": {
"id": "test-service",
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/demo/**"
}
}
],
"filters": [
{
"name": "SwaggerHeaderFilter",
"args": {}
},
{
"name": "StripPrefix",
"args": {
"_genkey_0": "1"
}
}
],
"uri": "lb://test",
"order": 0
},
"order": 0
}
]