Article directory
- 1. zuul and Gateway
- 2. Introduction to Gateway
- 3. Core Concept + Architecture Flow of Gateway
- 4. Gateway's build Gateway server + test
- 5. Two configuration methods of gateway routing
- 6. Configure dynamic routing for Gateway
- 7. Gateway's Predicate classification
- 8. Gateway's Filter(GatewayFilter)
- 9. Distributed Configuration Center of Spring Cloud Config (Introduction)
- 10. SpringCloud Config configuration control center construction (server)
- 11. SpringCloud Config configuration control center configuration and testing (client)
- 12. How does the configuration center of Spring Cloud Config solve the problem of dynamic refresh?
1. zuul and Gateway
Netflix has developed zuul.
Zuul has now stopped updating, and zuul2 was to be released before, and the development of zuul2 has been delayed.
Zuul has been doing the effect of gateway.
Gateway is the second-generation microservice gateway developed by SpringCloud, replacing zuul.
2. Introduction to Gateway
Location of Gateway:
The bottom layer of the SpringCloud Gateway gateway uses the netty communication framework:
What is webflux?
- The name of the WebFlux module is spring-webflux, and the Flux in the name comes from the class Flux in Reactor. Spring webflux has a new non-blocking functional Reactive web framework for building asynchronous, non-blocking, event-driven services that scale very well.
Project Architecture Diagram:
- Requests generally want to pass through nginx load balancing, and then enter the gateway cluster.
3. Core Concept + Architecture Flow of Gateway
The three core concepts of gateway gateway:
Gateway gateway architecture diagram:
- The core logic is:
路由转发 + 执行过滤器链
.
Official architecture diagram:
4. Gateway's build Gateway server + test
Step 1: Create a project and configure dependencies.
<!--引入gateway依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--添加eureka-client客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Step 2: Modify the application.yml file, add routing ID, routing address, and assertion.
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/get/** # 断言。 路径相匹配的进行路由。
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
# 表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
# 是否从eurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
# 入驻地址是哪个
defaultZone: http://eureka7001.com:7001/eureka # 单机
Precautions:
- Gateway gateway does not introduce springboot web and actuator dependencies.
Step 3: Start the project and test it.
5. Two configuration methods of gateway routing
The first one: as demonstrated above, configured in the configuration file yml.
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/get/** # 断言。 路径相匹配的进行路由。
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
The second: code injection routeLocator bean.
- The case visits Baidu's address.
package com.itholmes.springcloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GateWayConfig {
//使用注入bean的方式来修改网关的路由
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
// 这里映射百度的地址 , 目录为https://news.baidu.com/guonei
//这样访问http://localhost:9527/guonei 就会 访问到 https://news.baidu.com/guonei的信息
routes.route("path_route_itholmes",
r -> r.path("/guonei")
.uri("https://news.baidu.com/guonei"));
return routes.build();
}
}
6. Configure dynamic routing for Gateway
The routes we configured above are all hard-coded. By default, Gateway will create a dynamic route with the name of the microservice on the registry according to the service list registered in the registry for forwarding, so as to realize the function of dynamic routing.
- First enable the function of dynamically creating routes from the registry, and use the microservice name for routing.
- uri is configured as the microservice name corresponding to the registry.
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
# 开启从注册中心动态创建路由的功能,利用微服务名进行路由。
enabled: true
routes:
- id: payment_routh # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
# uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/get/** # 断言。 路径相匹配的进行路由。
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
# uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
# 表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
# 是否从eurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
# 入驻地址是哪个
defaultZone: http://eureka7001.com:7001/eureka # 单机
7. Gateway's Predicate classification
There are many kinds of Predicate assertions, just like adding where conditions, to determine whether the route meets the conditions:
For route predicates of three time ranges, route requests that match the time range:
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
# 开启从注册中心动态创建路由的功能,利用微服务名进行路由。
enabled: true
routes:
- id: payment_routh2 # 路由ID。 没有固定规则但要求唯一,建议配合服务名。
# uri: http://localhost:8001 # 路由地址。 匹配后提供服务的路由地址。
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
- After=2022-07-01T09:42:44.070+08:00[Asia/Shanghai] # 在这个时间之后的请求,才能正常通过路由。
- before=2022-07-01T09:42:44.070+08:00[Asia/Shanghai] # 在这个时间之前的请求,才能正常通过路由。
- Between=2022-07-01T09:42:44.070+08:00[Asia/Shanghai],2022-07-01T09:42:44.070+08:00[Asia/Shanghai] # 在这个时间之间,才能正常通过路由。
Cookie Route Predicate parameters:
predicates:
- Path=/payment/lb/** # 断言。 路径相匹配的进行路由。
- Cookie=username,zzyy # cookie,key是username,value是zzyy
With curl, you can test the effect of requests with and without cookies:
Header Route Predicate parameters:
- The meaning of the figure below: There must be an X-Request-Id request header in the request, and the value must conform to \d+ (regular, number).
Ditto:
Query Route Predicate:
8. Gateway's Filter(GatewayFilter)
This refers to the instance of GatewayFilter in the Spring framework. Using the filter, the request can be modified before or after the request is routed.
The life cycle of Spring Cloud Gateway's filter:
- pre and post. Front, rear.
Types of filters of Spring Cloud Gateway:
- Two kinds: GatewayFilter and GlobalFilter.
There are many different types of filters for GatewayFilter and GlobalFilter.
Custom global GatewayFilter filter:
- Two main interfaces: GloalFilter, Ordered.
- ordered is to determine the priority order, which filter is executed first.
- Through exchange acquisition, request and response, a series of operations are modified.
package com.itholmes.springcloud.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*******come in MyLogGateWayFilter: "+new Date());
//exchange.getRequest()
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null){
log.info("*********用户名为null,非法用户!");
//exchange.getResponse() , HttpStatus.NOT_ACCEPTABLE是不可用请求。
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
Mono<Void> voidMono = exchange.getResponse().setComplete();
return voidMono;
}
//放行,去下一个过滤链
return chain.filter(exchange);
}
@Override
public int getOrder() {
//order就是顺序,一般是数字越小,优先级越高。
return 0;
}
}
9. Distributed Configuration Center of Spring Cloud Config (Introduction)
Multiple microservices need the necessary configuration information to run, so it is essential to have a centralized and dynamic configuration management facility (meaning that application.yml can be configured uniformly).
Official explanation:
SpringCloud Config is divided into two parts: server and client.
Several functions of Spring cloud config:
SpringCloud Config uses Git by default to store configuration files (there are other ways of SVN, local files), and it is recommended to use Git.
10. SpringCloud Config configuration control center construction (server)
That is to build the following server:
Step 1: Create a new Repository repository named springcloud-config on Github. Get the git address. And clone the warehouse clone.
Step 2: Create a project and add dependencies.
<!--springcloud config配置中心的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--添加eureka-client客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Step 3: Modify the application.yml file.
- Configure the git related operations of config.
server:
port: 3344
spring:
application:
name: cloud-config-center # 微服务名称
cloud:
config:
server:
git:
uri: https://gitee.com/lixiaogou/sprincloud-config.git #GitHub上面的git仓库名字
search-paths: #搜索目录
- springcloud-config
label: master #读取分支
# 服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
Step 4: Add a startup class, add @EnableConfigServer //Enable the config service.
package com.itholmes.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer //开启config服务
public class ConfigCenterMain3344 {
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class,args);
}
}
The corresponding formula is as follows:
Official formula:
- The third one is recommended.
11. SpringCloud Config configuration control center configuration and testing (client)
SpringCloud Config has a client and a server.
Step 1: Create a project and add SpringCloud Config client dependencies.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Step 2: Create the bootstrap.yml configuration file.
- What is the bootstrap.yml configuration file?
server:
port: 3355
spring:
application:
name: config-client
cloud:
# SpringCloud Config 客户端配置
config:
label: master # 分支名称
name: config # 配置文件名称
profile: dev # 读取后缀名称
# 上述三个综合: master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 # 配置中心地址
# 服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
- In fact, the config client is to find the config server first, and the corresponding information is as follows:
Step 3: Test the interface, http://localhost:3355/configInfo.
package com.itholmes.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return configInfo;
}
}
The biggest problem is the dynamic refresh problem of distributed configuration:
- It means that when we modify the information on git, the config server will immediately respond to the corresponding modified data, but the config client has no response (unless the client system is restarted)!
12. How does the configuration center of Spring Cloud Config solve the problem of dynamic refresh?
Step 1: Add actuator monitoring dependencies.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Step 2: Expose monitoring endpoints.
server:
port: 3355
spring:
application:
name: config-client
cloud:
# SpringCloud Config 客户端配置
config:
label: master # 分支名称
name: config # 配置文件名称
profile: dev # 读取后缀名称
# 上述三个综合: master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
uri: http://localhost:3344 # 配置中心地址
# 服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: "*"
Step 3: Add the @RefreshScope annotation to the controller layer.
- Adding this annotation has the ability to refresh.
package com.itholmes.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return configInfo;
}
}
Note: The above content cannot be dynamically refreshed in the configuration, and the operation and maintenance personnel must send a Post request to refresh 3355!
Step 4: The operation and maintenance personnel send a Post request to refresh 3355.
- Execute the curl -X POST “http://localhost:3355/actuator/refresh” command to refresh.
Such a configuration is the pros and cons:
- Multiple servers need to send each request, which is very troublesome.
- Then there are 100 machines, and I want to change a few of them, which is also very troublesome to achieve.