Spring Zuul: Dynamically disable a route to a service

北慕城南 提交于 2019-12-04 16:06:04

Alternatively to using Cloud Config, custom ZuulFilter can be used. Something like (partial implementation to show the concept):

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;
    }

}

where blackList contains list of application IDs (Spring Boot application name) managed for example via some RESTful API.

After a lot of efforts I came up with this solution. First, I used Netflix Archaius to watch a property file. Then I proceeded as follows:

public class ApplicationRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

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


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

Made the doRefresh() method public by extending SimpleRouteLocator and calling its method in the overridden one of the interface RefreshableRouteLocator.

Then I redefined the bean RouteLocator with my custom implementation:

@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();
                        }



                }

}

Every time a property in the file was modified an event was triggered and the ConfigurationEvent was able to deal with it (getPropertyName() and getPropertyValue() to extract data from the event). Since I also Autowired the ZuulProperties I was able to get access to it. With the right rule I could find whether the property of Zuul

zuul.ignoredPatterns

was modified changing its value in the ZuulProperties accordingly.

Here refresh context should work (as long as you are not adding a new routing rule or removing a currently existing one), if you are adding or removing routing rules, you have to add a new bean for ZuulProperties and mark it with @RefreshScope, @Primary.

You can autowire refreshEndpoint bean for example and apply refreshEndpoint.refresh() on the listener.

Marking a custom RouteLocator as primary will cause problems as zuul already has bean of same type marked as primary.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!