Как сделать динамическую маршрутизацию Spring Cloud Zuul? Интеграция реализации Nacos проста

Spring Cloud
Как сделать динамическую маршрутизацию Spring Cloud Zuul? Интеграция реализации Nacos проста

1. Описание

Основной концепцией шлюза является конфигурация маршрутизации и правила маршрутизации.В качестве точки входа для всего трафика запросов, чтобы обеспечить высокую надежность и высокую доступность в реальной производственной среде, необходимо максимально избегать перезапуска, поэтому очень необходимо для реализации динамической маршрутизации; эта статья в основном знакомит с идеей реализации и использованияNacosОбъясните источник данных

 

2. Основные моменты реализации

Для реализации динамической маршрутизации нужно лишь обратить внимание на следующие 4 пункта

  1. Когда шлюз запустится,动态路由как загрузить данные
  2. 静态路由а также动态路由Что бы ни превалировало, ps:静态路由Относится к жестко запрограммированной конфигурации маршрутизации в файле конфигурации.
  3. монитор动态路由изменения источника данных
  4. Что происходит при изменении данных通知zuulобновить маршрут

 

В-третьих, конкретная реализация

3.1 Реализация загрузки данных для динамической маршрутизации

  • переписатьSimpleRouteLocatorКатегорияlocateRoutesМетод, этот метод предназначен для загрузки конфигурации маршрутизации, родительский класс должен получить конфигурацию маршрутизации в свойствах, вы можете расширить этот метод для достижения цели динамического получения конфигурации
  • используется здесь静态路由а также动态路由сосуществование, один и тот же идентификатор маршрута начинается с动态路由Реализация приоритетного покрытия

Класс AbstractDynRouteLocatorМожет просматривать:AbstractDynRouteLocator.java

public abstract class AbstractDynRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
    private ZuulProperties properties;

    public AbstractDynRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
    }

    /**
     * 刷新路由
     */
    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
        // 从application.properties中加载静态路由信息
        routesMap.putAll(super.locateRoutes());
        // 从数据源中加载动态路由信息
        routesMap.putAll(loadDynamicRoute());
        // 优化一下配置
        LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            // Prepend with slash if not already present.
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtils.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return values;
    }

    /**
     * 加载路由配置,由子类去实现
     */
    public abstract Map<String, ZuulRoute> loadDynamicRoute();
}

Поскольку данные динамической маршрутизации могут иметь множество видовспособ, такие как: Nacos, Redis, Zookeeper, DB и т. д., поэтому здесь определяется абстрактный класс, который определяется конкретным классом реализацииloadDynamicRouteметод

 

3.2 Класс реализации маршрутизации Nacos

Класс NacosDynRouteLocatorПолную реализацию кода можно посмотреть:NacosDynRouteLocator.java

3.2.1. РеализацияloadDynamicRouteметод получения динамических данных

    @Override
    public Map<String, ZuulProperties.ZuulRoute> loadDynamicRoute() {
        Map<String, ZuulRoute> routes = new LinkedHashMap<>();
        if (zuulRouteEntities == null) {
            zuulRouteEntities = getNacosConfig();
        }
        for (ZuulRouteEntity result : zuulRouteEntities) {
            if (StrUtil.isBlank(result.getPath()) || !result.isEnabled()) {
                continue;
            }
            ZuulRoute zuulRoute = new ZuulRoute();
            BeanUtil.copyProperties(result, zuulRoute);
            routes.put(zuulRoute.getPath(), zuulRoute);
        }
        return routes;
    }
		
    private List<ZuulRouteEntity> getNacosConfig() {
        try {
            String content = nacosConfigProperties.configServiceInstance().getConfig(ZUUL_DATA_ID, ZUUL_GROUP_ID,5000);
            return getListByStr(content);
        } catch (NacosException e) {
            log.error("listenerNacos-error", e);
        }
        return new ArrayList<>(0);
    }

3.2.2 ДополнениеNacosListenerМониторинг изменений данных маршрутизации

    private void addListener() {
        try {
            nacosConfigProperties.configServiceInstance().addListener(ZUUL_DATA_ID, ZUUL_GROUP_ID, new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    //赋值路由信息
                    locator.setZuulRouteEntities(getListByStr(configInfo));
                    RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(locator);
                    publisher.publishEvent(routesRefreshedEvent);
                }
            });
        } catch (NacosException e) {
            log.error("nacos-addListener-error", e);
        }
    }

УведомлениеПосле изменения маршрутных данных вам не нужно вручную обновлять маршрут самостоятельно, вам нужно только датьzuulОтправитьRoutesRefreshedEventмероприятие,zuulсобственныйZuulRefreshListener类Будет слушать события, чтобы помочь нам обновить маршрут

 

3.3 Создание класса конфигурацииNacosDynRouteLocatorБин

DynamicZuulRouteConfigМожет просматривать:NacosDynRouteLocator.java

@Configuration
@ConditionalOnProperty(prefix = "zlt.gateway.dynamicRoute", name = "enabled", havingValue = "true")
public class DynamicZuulRouteConfig {
    @Autowired
    private ZuulProperties zuulProperties;

    @Autowired
    private DispatcherServletPath dispatcherServletPath;

    /**
     * Nacos实现方式
     */
    @Configuration
    @ConditionalOnProperty(prefix = "zlt.gateway.dynamicRoute", name = "dataType", havingValue = "nacos", matchIfMissing = true)
    public class NacosZuulRoute {
        @Autowired
        private NacosConfigProperties nacosConfigProperties;

        @Autowired
        private ApplicationEventPublisher publisher;

        @Bean
        public NacosDynRouteLocator nacosDynRouteLocator() {
            return new NacosDynRouteLocator(nacosConfigProperties, publisher, dispatcherServletPath.getPrefix(), zuulProperties);
        }
    }
}

Здесь через пользовательскую конфигурацию, чтобы контролировать, открывать ли动态路由功能

 

3.4. ДобавитьNacosконфигурация маршрутизации

file
Новые элементы конфигурации:

  • Идентификатор данных: zuul-routes
  • Группа: ZUUL_GATEWAY
  • Содержание конфигурации:
[
    {
        "enabled":true,
        "id":"csdn",
        "path":"/csdn/**",
        "retryable":false,
        "stripPrefix":true,
        "url":"https://www.csdn.net/"
    }, {
        "enabled":true,
        "id":"github",
        "path":"/github/**",
        "retryable":false,
        "stripPrefix":true,
        "url":"http://github.com/"
    }
]

Добавьте два маршрутных данных

 

4. Тест

  • Запустите шлюз через/actuator/routesКонечные точки просматривают текущую информацию о маршрутизации
    file

Вы можете видеть статические маршруты иNacosДве информации о маршрутизации, настроенные в файле, отображаются рядом.

  • ИсправлятьNacosнастроить, закрытьcsdnмаршрутизация
    file
  • Обновите, чтобы просмотреть информацию о маршрутизации шлюза.
    file

csdnМаршрут больше не виден, а конфигурация маршрутизации динамически изменяется.

  Рекомендуемое чтение

  Пожалуйста, отсканируйте код, чтобы подписаться на мой официальный аккаунт

file