Spring Zuul: динамическое отключение маршрута к сервису

#spring-boot #java-8 #netflix-zuul #netflix-eureka

#spring-boot #java-8 #netflix-zuul #netflix-eureka

Вопрос:

Я пытаюсь отключить маршрут Zuul к микросервису, зарегистрированному в Eureka во время выполнения (я использую spring boot).

Это пример:

 localhost/hello
localhost/world
  

Эти два являются зарегистрированными микросервисами. Я хотел бы отключить маршрут к одному из них во время выполнения, не отключая его.

Есть ли способ сделать это?

Спасибо,

Nano

Комментарии:

1. Под динамически вы подразумеваете с помощью кода … если вы используете cloud config, то вы можете удалить маршрутизацию из свойств zuul и обновить ее через actuator, тогда маршрутизация не произойдет… для меня это звучит динамично…

Ответ №1:

В качестве альтернативы использованию облачной конфигурации можно использовать пользовательскую ZuulFilter . Что-то вроде (частичная реализация, чтобы показать концепцию):

 public class BlackListFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "pre";
    }
    ...
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String uri = ctx.getRequest().getRequestURI();
        String appId = uri.split("/")[1];
        if (blackList.contains(appId)) {
            ctx.setSendZuulResponse(false);
            LOG.info("Request '{}' from {}:{} is blocked",
                    uri, ctx.getRequest().getRemoteHost(), ctx.getRequest().getRemotePort());
        }
        return null;
    }

}
  

где blackList содержится список идентификаторов приложений (имя приложения Spring Boot), управляемых, например, через некоторый RESTful API.

Комментарии:

1. Я тоже думал о фильтре, но хотел попробовать использовать собственные свойства Zuul 🙂

Ответ №2:

После долгих усилий я пришел к этому решению. Сначала я использовал Netflix Archaius для просмотра файла свойств. Затем я поступил следующим образом:

 public class ApplicationRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

public ApplicationRouteLocator(String servletPath, ZuulProperties properties) {
    super(servletPath, properties );
}


@Override
public void refresh() {
   doRefresh();
}
}
  

Сделал метод doRefresh() общедоступным, расширив SimpleRouteLocator и вызвав его метод в переопределенном интерфейсе RefreshableRouteLocator.

Затем я переопределил bean RouteLocator с помощью своей пользовательской реализации:

 @Configuration
@EnableConfigurationProperties( { ZuulProperties.class } )
public class ZuulConfig {

public static ApplicationRouteLocator simpleRouteLocator;

@Autowired
private ZuulProperties zuulProperties;

@Autowired
private ServerProperties server;

@Bean
@Primary
public RouteLocator routeLocator() {
    logger.info( "zuulProperties are: {}", zuulProperties );
    simpleRouteLocator = new ApplicationRouteLocator( this.server.getServletPrefix(),
            this.zuulProperties );


    ConfigurationManager.getConfigInstance().addConfigurationListener( configurationListener );

    return simpleRouteLocator;
}


private ConfigurationListener configurationListener =
        new ConfigurationListener() {

            @Override
            public void configurationChanged( ConfigurationEvent ce ) {

                            // zuulProperties.getRoutes() do something
                            // zuulProperties.getIgnoredPatterns() do something
                            simpleRouteLocator.refresh();
                        }



                }

}
  

Каждый раз, когда свойство в файле изменялось, запускалось событие, и ConfigurationEvent мог справиться с ним (getPropertyName() и GetPropertyValue() для извлечения данных из события). Поскольку я также автоматически подключил свойства ZuulProperties, я смог получить к нему доступ. С правильным правилом я мог бы определить, является ли свойство Zuul

 zuul.ignoredPatterns
  

был изменен, соответствующим образом изменив его значение в ZuulProperties.

Комментарии:

1. Не удается разрешить метод ‘getServletPrefix’ в ‘ServerProperties’

Ответ №3:

Здесь должен сработать контекст обновления (пока вы не добавляете новое правило маршрутизации или не удаляете существующее в данный момент), если вы добавляете или удаляете правила маршрутизации, вам нужно добавить новый компонент для ZuulProperties и пометить его @RefreshScope, @Primary.

Например, вы можете автоматически подключить компонент refreshEndpoint и применить refreshEndpoint.refresh() к прослушивателю.

Пометка пользовательского RouteLocator как основного вызовет проблемы, поскольку в zuul уже есть компонент того же типа, помеченный как основной.