1. Description
The core concept of gateway is routing configuration and routing rules. As the entrance of all requests traffic, dynamic routing is necessary to avoid rebooting in the real production environment in order to ensure high reliability and high availability. This paper mainly introduces the idea of implementation and uses Nacos as the data source.explain
2. Implementing Key Points
To achieve dynamic routing, you only need to focus on the following four points
- How the dynamically routed data is loaded when the gateway starts
- Static and dynamic routing are predicated on that, ps: Static routing refers to the write-dead routing configuration in the configuration file
- Listening for data source changes in dynamic routing
- How to notify zuul to refresh routes when data changes
3. Specific implementation
3.1. Data loading for dynamic routing
- Overrides the locateRoutes method of the SimpleRouteLocator class, which loads routing configurations, and gets routing configurations in properties from the parent class, which can be extended to achieve the purpose of dynamically obtaining configurations
- Here, static and dynamic routes coexist, and the implementation of dynamic route-first override with the same route id
The AbstractDynRouteLocator class can be viewed: 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; } /** * Refresh Route */ @Override public void refresh() { doRefresh(); } @Override protected Map<String, ZuulRoute> locateRoutes() { LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>(); // Loading static routing information from application.properties routesMap.putAll(super.locateRoutes()); // Loading dynamic routing information from a 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; } /** * Load routing configuration, implemented by subclasses */ public abstract Map<String, ZuulRoute> loadDynamicRoute(); }
Since dynamically routed data can be routed in many ways, such as Nacos, Redis, Zookeeper, DB, and so on, an abstract class is defined here, and the loadDynamicRoute method is defined by a specific implementation class.
3.2. Nacos Routing Implementation Class
The complete code implementation of the NacosDynRouteLocator class can be viewed: NacosDynRouteLocator.java
3.2.1. Implementing the loadDynamicRoute method 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() { 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. Increase NacosListener to listen for routing data changes
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) { //Assignment Routing Information locator.setZuulRouteEntities(getListByStr(configInfo)); RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(locator); publisher.publishEvent(routesRefreshedEvent); } }); } catch (NacosException e) { log.error("nacos-addListener-error", e); } }
Notice that you don't need to refresh the route manually after the route data changes, just send a RoutesRefreshedEvent event to zuul, who has his own ZuulRefreshListener class to listen for events to help us refresh the route
3.3. Configuration class creates Bean for NacosDynRouteLocator
DynamicZuulRouteConfig can be viewed: 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() { return new NacosDynRouteLocator(nacosConfigProperties, publisher, dispatcherServletPath.getPrefix(), zuulProperties); } } }
Custom configuration controls whether dynamic routing is enabled or not
3.4. Add Nacos routing configuration
Add a new configuration item:
- Data Id: zuul-routes
- Group: ZUUL_GATEWAY
- Configuration:
[ { "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/" } ]
Add two routes
IV. Testing
- Start gateway to view current routing information through/actuator/routes endpoint
You can see that the static route and the two route information configured in Nacos are displayed side by side
- Modify Nacos configuration to turn off csdn routing
- Refresh View Gateway Routing Information
csdn's routing is no longer visible and dynamic routing configuration changes are implemented
Recommended reading
- Is log troubleshooting difficult?Distributed log link tracking to help you
- zuul integrates Sentinel's latest gateway flow control components
- Ali Registry Nacos Production Deployment Plan
- Spring Boot Custom Configuration Enables Automatic Prompt in IDE
Please scan my public number