A, description,

The core concept of gateway is routing configuration and routing rules. As the entrance of all request traffic, it is necessary to avoid restarts in the actual production environment to ensure high reliability and availability. Therefore, dynamic routing is very necessary. This article mainly introduces the implementation ideas, and Nacos as the data source to explain

 

2. Key points of implementation

To implement dynamic routing, focus on the following four points

  1. When the gateway is started,Dynamic routingHow is the data loaded in
  2. Static routingwithDynamic routingPs:Static routingThis refers to the route configuration that is written to death in the configuration file
  3. Listening to theDynamic routingData source changes of
  4. What happens when the data changesInform zuulThe refresh routing

 

Third, concrete implementation

3.1. Realize data loading of dynamic routing

  • rewriteSimpleRouteLocatorOf the classlocateRoutesMethod, this method is to load the route configuration, the parent class is to obtain the route configuration in the properties, you can extend this method, to achieve the purpose of dynamic obtain configuration
  • Here theStatic routingwithDynamic routingCoexist with the same route IDDynamic routingImplementation of priority coverage

AbstractDynRouteLocator class to view: 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(a) {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulRoute> locateRoutes(a) {
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
        // Load static routing information from application.properties
        routesMap.putAll(super.locateRoutes());
        // Load dynamic routing information from the data source
        routesMap.putAll(loadDynamicRoute());
        // Optimize the configuration
        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;
    }

    /** * loads the route configuration, which is implemented by subclasses */
    public abstract Map<String, ZuulRoute> loadDynamicRoute(a);
}
Copy the code

Because dynamic routing data can be in many ways, such as: Nacos, Redis, Zookeeper, DB, etc., so here defines an abstract class, by the concrete implementation class to define loadDynamicRoute method

 

3.2. Nacos Routing implementation class

NacosDynRouteLocator class complete code can be viewed: NacosDynRouteLocator. Java

3.2.1. AchieveloadDynamicRouteMethod to obtain dynamic data

    @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(a) {
        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);
    }
Copy the code

Increased 3.2.2.NacosListenerMonitor routing data changes

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

                @Override
                public void receiveConfigInfo(String configInfo) {
                    // Assign routing information
                    locator.setZuulRouteEntities(getListByStr(configInfo));
                    RoutesRefreshedEvent routesRefreshedEvent = newRoutesRefreshedEvent(locator); publisher.publishEvent(routesRefreshedEvent); }}); }catch (NacosException e) {
            log.error("nacos-addListener-error", e); }}Copy the code

Zuul has a ZuulRefreshListener class that listens for the event to refresh the route for us

 

3.3. Configuration class creationNacosDynRouteLocatorThe Bean

DynamicZuulRouteConfig to view: NacosDynRouteLocator. Java

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

    @Autowired
    private DispatcherServletPath dispatcherServletPath;

    /** * Nacos implementation */
    @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(a) {
            return newNacosDynRouteLocator(nacosConfigProperties, publisher, dispatcherServletPath.getPrefix(), zuulProperties); }}}Copy the code

You can customize the configuration to control whether to enable dynamic routing

 

Add 3.4.NacosThe routing configuration

  • Data Id: zuul – routes
  • Group: ZUUL_GATEWAY
  • Configuration contents:
[{"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/"}]Copy the code

Add two routes

 

Four, test,

  • Enabling the Gateway/actuator/routesThe endpoint displays the current routing information

You can see that static routes and the two routes configured in Nacos are displayed together

  • Modify theNacosConfigure, closecsdnrouting
  • Refresh View gateway routing information

CSDN routes are no longer visible, and dynamic route configuration is changed

Recommended reading

  • Log troubleshooting difficulty? Distributed log link tracing to help you
  • Zuul integrates Sentinel’s latest gateway flow control components
  • Ali Registry Nacos production deployment solution
  • Spring Boot custom configuration items implement automatic prompts in the IDE

Please scan the code to follow my official account