Nacos+Spring Cloud Gateway Dynamic Routing Configuration

Preface Nacos has recently been working on p...
1. Start Nacos Configuration Center and create routing configuration
2. Connect Nacos Configuration Center
1. Project structure
1. Start the service and observe the registry
2. Access gateways and view service logs
Preface

Nacos has recently been working on projects that are simple, flexible, support finer-grained command spaces, grouping, and so on, to facilitate complex environment switching, while also supporting the configuration of dynamic routing in a few simple steps.It is prominent and easy to get started in the domestic registration and configuration centers. This paper shows three simple modules: gateway, nacos-consumer and nacos-provider: dynamic routing configuration under Nacos.

I. Nacos Environmental Preparation

1. Start Nacos Configuration Center and create routing configuration

Specific Nacos configuration is not described, you can refer to Alibaba's official introduction, here through windows direct local boot to open single-machine mode, log in to Nacos Console, create dev namespace, create gateway-router dataId under default grouping under dev

The main initialization configuration of gateway-router is as follows: about the composition of gateway (id, order, predicates assertion, uri) is not detailed here, you can go under Baidu yourself

[{ "id": "consumer-router", "order": 0, "predicates": [{ "args": { "pattern": "/consume/**" }, "name": "Path" }], "uri": "lb://nacos-consumer" },{ "id": "provider-router", "order": 2, "predicates": [{ "args": { "pattern": "/provide/**" }, "name": "Path" }], "uri": "lb://nacos-provider" }]

2. Connect Nacos Configuration Center

Configuration centers are usually configured in bootstrap.propertis(yaml) in a project to ensure that the routing configuration in the project is read from Nacos Config.

# The nacos Configuration Center configuration recommendation is configured in bootstrap.properties spring.cloud.nacos.config.server-addr=127.0.0.1:8848 #spring.cloud.nacos.config.file-extension=properties # Configuration Center namespace: dev's namespace (environment) spring.cloud.nacos.config.namespace=08ecd1e5-c042-410a-84d5-b0a8fbeed8ea

Add the comment @EnableDiscoveryClient to the Application startup class to ensure a connection to Nacos Config

@SpringBootApplication @EnableDiscoveryClient public class GatewayApplication { public static void main( String[] args ) { SpringApplication.run(GatewayApplication.class, args); } }

2. Project Construction

1. Project structure

Create a simple spring boot multimodule structure, idea is recommended

1) Nacos parent module:

<groupId>com.springcloud</groupId> <artifactId>nacos</artifactId> <version>0.0.1-SNAPSHOT</version> <name>nacos</name> <description>Nacos Demo</description>

First the pom file introduces the Spring Cloud Alibaba Nacos component: registry nacos-discovery and configuration center nacos-config

<!--nacos Client Registry--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>$</version> </dependency> <!--nacos Client Configuration Center--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>$</version> </dependency>

Second, introduce Spring Cloud-related component dependencies

<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>$</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>$</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

Other components depend on the introduction of:

<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>$</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>$</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>$</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>

Note that there is a pit here, the web framework used by the spring cloud gateway is webflux, which is not compatible with springMVC.Do not introduce

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

2) Three sub-modules: gateway, nacos-consumer, nacos-provider

<modules> <module>nacos-provider</module> <module>nacos-consumer</module> <module>gateway</module> </modules>

The structure screenshot is as follows:

3) The ports of the three services are:

nacos-consume:6001

nacos-provider:6002

gateway: 6003

4) The service architecture is as follows:

2. Write test code

(1) In the gateway module, the main functions are as follows:

First, loading configurations related to dynamic routing from the Nacos Configuration Center requires reading Nacos's namespace to obtain configurations via dataId

/** * Routing Class Configuration */ @Configuration public class GatewayConfig { public static final long DEFAULT_TIMEOUT = 30000; public static String NACOS_SERVER_ADDR; public static String NACOS_NAMESPACE; public static String NACOS_ROUTE_DATA_ID; public static String NACOS_ROUTE_GROUP; @Value("$") public void setNacosServerAddr(String nacosServerAddr){ NACOS_SERVER_ADDR = nacosServerAddr; } @Value("$") public void setNacosNamespace(String nacosNamespace){ NACOS_NAMESPACE = nacosNamespace; } @Value("$") public void setNacosRouteDataId(String nacosRouteDataId){ NACOS_ROUTE_DATA_ID = nacosRouteDataId; } @Value("$") public void setNacosRouteGroup(String nacosRouteGroup){ NACOS_ROUTE_GROUP = nacosRouteGroup; } }

Properrties configuration About reading gateway-router configuration under Nacos:

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 spring.cloud.nacos.discovery.namespace=08ecd1e5-c042-410a-84d5-b0a8fbeed8ea nacos.gateway.route.config.data-id=gateway-router nacos.gateway.route.config.group=DEFAULT_GROUP

Second, initialize routes to monitor data source changes in dynamic routing configuration;

/** * * Monitor gateway-route configuration in Nacos by launching dynamic routing configuration under Nacos * */ @Component @Slf4j @DependsOn({"gatewayConfig"}) // Dependent on gatewayConfig bean public class DynamicRouteServiceImplByNacos { @Autowired private DynamicRouteServiceImpl dynamicRouteService; private ConfigService configService; @PostConstruct public void init() { log.info("gateway route init..."); try{ configService = initConfigService(); if(configService == null){ log.warn("initConfigService fail"); return; } String configInfo = configService.getConfig(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP, GatewayConfig.DEFAULT_TIMEOUT); log.info("Get Gateway Current Configuration:\r\n{}",configInfo); List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class); for(RouteDefinition definition : definitionList){ log.info("update route : {}",definition.toString()); dynamicRouteService.add(definition); } } catch (Exception e) { log.error("Error initializing gateway route",e); } dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID,GatewayConfig.NACOS_ROUTE_GROUP); } /** * Listen for dynamic routing configuration from Nacos * @param dataId * @param group */ public void dynamicRouteByNacosListener (String dataId, String group){ try { configService.addListener(dataId, group, new Listener() { @Override public void receiveConfigInfo(String configInfo) { log.info("Update Gateway:\n\r{}",configInfo); List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class); for(RouteDefinition definition : definitionList){ log.info("update route : {}",definition.toString()); dynamicRouteService.update(definition); } } @Override public Executor getExecutor() { log.info("getExecutor\n\r"); return null; } }); } catch (NacosException e) { log.error("from nacos Receive Dynamic Routing Configuration Error!!!",e); } } /** * Initialize gateway route nacos config * @return */ private ConfigService initConfigService(){ try{ Properties properties = new Properties(); properties.setProperty("serverAddr",GatewayConfig.NACOS_SERVER_ADDR); properties.setProperty("namespace",GatewayConfig.NACOS_NAMESPACE); return configService= NacosFactory.createConfigService(properties); } catch (Exception e) { log.error("Error initializing gateway route",e); return null; } } }

Third, refresh the latest dynamic routing changes to achieve dynamic add-delete routing

/** * Dynamic Update Routing Gateway service * 1)Implement an event push interface provided by Spring ApplicationEventPublisherAware * 2)Provides the basic method of dynamic routing by getting a bean to manipulate the methods of this class.This class provides new routes, updates routes, deletes routes, and then implements the functions of publishing. */ @Slf4j @Service public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware { @Autowired private RouteDefinitionWriter routeDefinitionWriter; /** * Publish Events */ @Autowired private ApplicationEventPublisher publisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; } /** * Delete Route * @param id * @return */ public String delete(String id) { try { log.info("gateway delete route id {}",id); this.routeDefinitionWriter.delete(Mono.just(id)); return "delete success"; } catch (Exception e) { return "delete fail"; } } /** * Update Route * @param definition * @return */ public String update(RouteDefinition definition) { try { log.info("gateway update route {}",definition); this.routeDefinitionWriter.delete(Mono.just(definition.getId())); } catch (Exception e) { return "update fail,not find route routeId: "+definition.getId(); } try { routeDefinitionWriter.save(Mono.just(definition)).subscribe(); this.publisher.publishEvent(new RefreshRoutesEvent(this)); return "success"; } catch (Exception e) { return "update route fail"; } } /** * Add Routing * @param definition * @return */ public String add(RouteDefinition definition) { log.info("gateway add route {}",definition); routeDefinitionWriter.save(Mono.just(definition)).subscribe(); this.publisher.publishEvent(new RefreshRoutesEvent(this)); return "success"; } }

(2) Create a ConsumeController at consumer: Jump to the nacos-consumer service ("uri": "lb://nacos-consumer") by accessing the gateway gateway/consume/sayHello/("pattern": "/consume/**"),

@RequestMapping("/consume/") @Slf4j public class ConsumeController { @GetMapping("/sayHello/") public String sayHello(@PathVariable("name") String name){ log.info("I'm calling nacos-consumer service by dynamic gateway..."); return name + " Hi~, I'm from nacos-consumer"; } }

(3) Create ProviderController in provider: Jump to nacos-provider service by accessing gateway gateway/provide/sayHello/ ("pattern": "/provide/**") ("uri": "lb://nacos-provider")

@RestController @RequestMapping("/provide/") @Slf4j public class ProviderController { @GetMapping("/sayHello/") public String sayHello(@PathVariable("name") String name){ log.info("I'm calling nacos-provider service by dynamic gateway..."); return name + " Hi~, I'm from nacos-provider"; } }
3. Testing Dynamic Gateway Configuration

1. Start the service and observe the registry

Start gateway, nacos-consumer, and nacos-provider services to see if they are registered correctly on Nacos

Note: You need to specify that the namespace of the registry is dev space, that is, spring.cloud.nacos.discovery.namespace=08ecd1e5-c042-410a-84d5-b0a8fbeed8ea

2. Access gateways and view service logs

(1) View the initial startup log of the gateway service: you will find that the content of the configuration gateway-router gateway configuration file can be normally obtained from Nacos and loaded with the correct route...

2020-05-10 14:33:44.557 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : gateway route init... 2020-05-10 14:33:44.578 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : Get Gateway Current Configuration: [{ "id": "consumer-router", "order": 0, "predicates": [{ "args": { "pattern": "/consume/**" }, "name": "Path" }], "uri": "lb://nacos-consumer" },{ "id": "provider-router", "order": 2, "predicates": [{ "args": { "pattern": "/provide/**" }, "name": "Path" }], "uri": "lb://nacos-provider" }] 2020-05-10 14:33:44.691 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}} 2020-05-10 14:33:44.691 INFO 1272 --- [ main] c.g.service.DynamicRouteServiceImpl : gateway add route RouteDefinition}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}} 2020-05-10 14:33:45.192 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [After] 2020-05-10 14:33:45.192 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Before] 2020-05-10 14:33:45.192 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Between] 2020-05-10 14:33:45.193 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Cookie] 2020-05-10 14:33:45.193 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Header] 2020-05-10 14:33:45.193 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Host] 2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Method] 2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Path] 2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Query] 2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [ReadBodyPredicateFactory] 2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [RemoteAddr] 2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [Weight] 2020-05-10 14:33:45.194 INFO 1272 --- [ main] o.s.c.g.r.RouteDefinitionRouteLocator : Loaded RoutePredicateFactory [CloudFoundryRouteService] 2020-05-10 14:33:45.335 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition}], filters=[], uri=lb://nacos-provider, order=2, metadata={}} 2020-05-10 14:33:45.335 INFO 1272 --- [ main] c.g.service.DynamicRouteServiceImpl : gateway add route RouteDefinition}], filters=[], uri=lb://nacos-provider, order=2, metadata={}} 2020-05-10 14:33:45.336 INFO 1272 --- [ main] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition}], filters=[], uri=https://github.com, order=3, metadata={}} 2020-05-10 14:33:45.336 INFO 1272 --- [ main] c.g.service.DynamicRouteServiceImpl : gateway add route RouteDefinition}], filters=[], uri=https://github.com, order=3, metadata={}}

But this only means initializing static routes. Let's change the gateway-router gateway configuration to append github-router routes

[{ "id": "consumer-router", "order": 0, "predicates": [{ "args": { "pattern": "/consume/**" }, "name": "Path" }], "uri": "lb://nacos-consumer" },{ "id": "provider-router", "order": 2, "predicates": [{ "args": { "pattern": "/provide/**" }, "name": "Path" }], "uri": "lb://nacos-provider" },{ "id": "github-router", "order": 2, "predicates": [{ "args": { "pattern": "/github/**" }, "name": "Path" }], "uri": "https://github.com" }]

Then click Publish to update the routing configuration

Watch the gateway service log for any monitoring and correct routing updates: As shown in the following log, the latest routing configuration is printed immediately and the correct routing updates are made

2020-05-10 14:42:27.576 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos : Update Gateway: [{ "id": "consumer-router", "order": 0, "predicates": [{ "args": { "pattern": "/consume/**" }, "name": "Path" }], "uri": "lb://nacos-consumer" },{ "id": "provider-router", "order": 2, "predicates": [{ "args": { "pattern": "/provide/**" }, "name": "Path" }], "uri": "lb://nacos-provider" },{ "id": "github-router", "order": 2, "predicates": [{ "args": { "pattern": "/github/**" }, "name": "Path" }], "uri": "https://github.com" }] 2020-05-10 14:42:27.576 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}} 2020-05-10 14:42:27.576 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.service.DynamicRouteServiceImpl : gateway update route RouteDefinition}], filters=[], uri=lb://nacos-consumer, order=0, metadata={}} 2020-05-10 14:42:27.578 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition}], filters=[], uri=lb://nacos-provider, order=2, metadata={}} 2020-05-10 14:42:27.578 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.service.DynamicRouteServiceImpl : gateway update route RouteDefinition}], filters=[], uri=lb://nacos-provider, order=2, metadata={}} 2020-05-10 14:42:27.580 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.r.DynamicRouteServiceImplByNacos : update route : RouteDefinition}], filters=[], uri=https://github.com, order=2, metadata={}} 2020-05-10 14:42:27.580 INFO 1272 --- [d5-b0a8fbeed8ea] c.g.service.DynamicRouteServiceImpl : gateway update route RouteDefinition}], filters=[], uri=https://github.com, order=2, metadata={}}

In fact, there is also a way to know if our gateway service is listening on Nacos's gateway-router configuration, that is, in Nacos Console ---> Listen for Queries ---> Select Configuration --> Enter the namespace and Group of the configuration file: you can see that my local IP address 127.0.0.1 is listening on the configuration file gateway-router

(2) Access gateway gateway services: http://localhost:6003/consume/sayHello/nacos

View the consumer service log:

2020-05-10 14:55:07.257 INFO 6552 --- [nio-6001-exec-2] c.n.c.controller.ConsumeController : I'm calling nacos-consumer service by dynamic gateway...

Discovery jumped to consumer service and accessed CosnumerController of consumer service

(3) Access gateway gateway services: http://localhost:6003/provider/sayHello/nacos

View the provider service log:

2020-05-10 14:56:56.144 INFO 10024 --- [nio-6002-exec-1] c.n.p.controller.ProviderController : I'm calling nacos-provider service by dynamic gateway...

Discovery jumped to consumer service and accessed ProviderController of provider service

(4) Access the Access gateway Service: http://localhost:6003/ github, jump to github page correctly

4. Summary

1) Spring Cloud Gateway not only serves as a simple redirection jump, but also enables users to authenticate and log on, resolves cross-domain, log interception, permission control, flow limiting, melting, load balancing, blacklist and whitelist mechanisms.It is the best choice for microservice architecture.

2) The configuration center of Nacos supports dynamic configuration file acquisition. It can place some global and frequently changing configuration files under Nacos and need to go to the microservice to get them by itself.

10 May 2020, 04:07 | Views: 5617

Add new comment

For adding a comment, please log in
or create account

0 comments