SpringCloudAlibaba Gateway (1) Simple integration
As the service module increases, multiple interface addresses will inevitably be generated. Then the client can only use multiple addresses when calling multiple interfaces. It is very inconvenient to maintain multiple addresses. At this time, the service address needs to be unified. At the same time, unified authentication and authentication requirements can also be implemented. Then the service gateway plays such a role.
Gateway
The gateway stands in front of many microservices and performs functions such as routing and forwarding, monitoring, current limiting, and authentication. SpringCloudGateway is one of its implementations. SpringCloudGateway
Drawing on the ideas of Spring Cloud Netfilix Zuul, its goal is to replace Zuul.
Gateway
It is WebFlux
implemented based on a framework, and the bottom layer of WebFlux uses a high-performance framework Netty
. The performance is 1.6 times that of Zuul, with powerful functions and elegant design.
The core of Gateway is 路由
, Predicate(断言)
, Filter(过滤器)
. Routing is a forwarding rule, Predicate is a judgment, and Filter can be thought of as adding a little custom logic before or after the request is routed.
SpringCloudGateway requires SpringBoot2.0+ and above, and cannot be run in Servlet containers such as Tomcat or Jetty. It must be run as a Jar package! ! !
Integrate Gateway
Build a Gateway service and create two services: user service and product service. The architecture is as follows:
user serviceUserController,用户服务端口8002
@RestController
public class UserController {
private final Map<Integer, String> userInfo = new HashMap<Integer, String>() {
{
put(1, "Zhangsan");
put(2, "Lisi");
}};
@RequestMapping("/user/findById")
public String findById(@RequestParam("id") Integer id) {
return userInfo.getOrDefault(id, null);
}
}
shop serviceShopController,商品服务端口8003
@RestController
public class ShopController {
private final Map<Integer, String> shopInfo = new HashMap<Integer, String>() {
{
put(1, "这是苹果");
put(1024, "芒果");
}};
@RequestMapping("/shop/findById")
public String findById(@RequestParam("id") Integer id) {
return shopInfo.getOrDefault(id, null);
}
}
Create a gateway service
rely
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
Remove spring-boot-starter-web
the dependency in Gateway. There is webflux dependency in gateway, which starter-web
conflicts with it.
bootstrap.yml
Add configuration
server:
port: 8083
spring:
application:
name: gateway # 服务名
cloud:
gateway:
routes: # 路由,可配置多个
- id: user_route # 路由id,唯一即可,默认UUID
uri: http://localhost:8002 # 路由地址(匹配成功后的服务地址)
order: 1 # 路由优先级,默认0,越低优先级越高
predicates:
- Path=/user/** # 断言,匹配规则
- id: shop_route
uri: http://localhost:8003
order: 1
predicates:
- Path=/shop/**
Gateway configuration can also use JavaConfig, but it is not recommended.
The configuration indicates that when 网关
the address in the request path starts with, it will /user/
be routed to the user service, and if the address starts with, /shop/
it will be routed to the product service.
have a test
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
Zhangsan
C:\Users\Admin>curl http://localhost:8083/shop/findById?id=1024
芒果
Gateway integrates nacos
In the above case, the uri is something hard-coded. If the corresponding specific service address is changed, then the configuration file needs to be modified. Moreover, if you want to increase the user capacity and do load balancing, there are many nodes, and you must not just configure it. A service address.
Then you need to use nacos to uniformly manage service registration and discovery. The address for gateway routing and forwarding can be obtained from nacos.
Then 用户服务
it is 商品服务
necessary to introduce nacos service discovery registration dependency
<!-- 服务注册 服务发现需要引入的 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--健康监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
bootstrap.yml file
------------------------User服务
server:
port: 8002
spring:
application:
name: user # 应用名
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos服务地址
--------------------------Shop服务
server:
port: 8003
spring:
application:
name: shop # 应用名
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos服务地址
Finally, remember to start the nacos service registration discovery in the startup class.
@SpringBootApplication
@EnableDiscoveryClient // 启用服务注册发现
public class UserApp {
public static void main(String[] args) {
SpringApplication.run(UserApp.class, args);
}
}
Ok, then similarly, the gateway service must also enable service registration discovery.
rely
<!-- 服务注册 服务发现需要引入的 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
bootstrap.yml
The configuration is as follows:
server:
port: 8083
spring:
application:
name: gateway # 服务名
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos地址
gateway:
discovery:
locator:
enabled: true # 让gateway可以发现nacos中的服务,gateway自动根据服务发现为每一个服务创建了一个router,# 这个router将以服务名开头的请求路径转发到对应的服务
routes: # 路由,可配置多个
- id: user_route # 路由id,唯一即可,默认UUID
uri: lb://user # 路由地址(匹配成功后的服务地址) user是用户服务的服务名称
order: 1 # 路由优先级,默认0,越低优先级越高
predicates:
- Path=/user/** # 断言,匹配规则
- id: shop_route
uri: lb://shop # 路由地址(匹配成功后的服务地址) shop是商品服务的服务名称
order: 1
predicates:
- Path=/shop/**
Try starting:
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
{
"timestamp":"2023-08-05T00:34:40.684+00:00","path":"/user/findById","status":503,"error":"Service Unavailable","requestId":"f5f6d217-1"}
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
{
"timestamp":"2023-08-05T00:35:50.223+00:00","path":"/user/findById","status":503,"error":"Service Unavailable","requestId":"21a722a2-1"}
ha? The service is unavailable. After consulting the information, we learned that ReactiveLoadBalancerClientFilter
filters are missing and LoadBalancerClientFactory
classes are required, but related dependencies need to be introduced.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
Okay, try again:
C:\Users\Admin>curl http://localhost:8083/shop/findById?id=1024
{
"timestamp":"2023-08-05T01:19:34.183+00:00","status":404,"error":"Not Found","path":"/findById"}
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
{
"timestamp":"2023-08-05T01:19:34.183+00:00","status":404,"error":"Not Found","path":"/findById"}
So beautiful, I stepped on a big trap! ! ! 404 all the time! ! !
After struggling in every possible way, checking information, looking at the source code, debugging, etc., I understand the reason...
spring:
application:
name: gateway # 服务名
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos地址
gateway:
discovery:
locator:
enabled: true # 让gateway可以发现nacos中的服务,gateway自动根据服务发现为每一个服务创建了一个router,# 这个router将以服务名开头的请求路径转发到对应的服务
Here comes the key point. Pay attention:
When your gateway is configured locator.enabled: true
, the gateway automatically creates a router for each service based on service discovery. This router will forward the request path starting with the service name to the corresponding service 相当于人家给你自动生成了route规则,你自己都不用配置了
.
However: your request must include the service name of the server before you can access it.
Take the above as an example: If you want to access user
the service /user/findById
, the request address islocalhost:8083/user/user/findById
C:\Users\Admin>curl http://localhost:8083/user/user/findById?id=1
Zhangsan
how to choose
Two writing methods are provided:
-
In fact, if the project path is relatively simple, just use gateway and
自动生成
nacosspring: application: name: gateway # 服务名 cloud: nacos: discovery: server-addr: localhost:8848 # nacos地址 gateway: discovery: locator: enabled: true # 让gateway可以发现nacos中的服务,gateway自动根据服务发现为每一个服务创建了一个router,# 这个router将以服务名开头的请求路径转发到对应的服务
When requesting, remember to bring the name of the server
application.name
. For examplelocahost:8083/user/user/findById
, the first oneuser
is the service name. -
If you don't want to do this and want to jump directly to the corresponding service using a path without writing the service name, then we need to customize routes.
server: port: 8083 spring: application: name: gateway # 服务名 cloud: nacos: discovery: server-addr: localhost:8848 # nacos地址 gateway: routes: # 路由,可配置多个 - id: user_route # 路由id,唯一即可,默认UUID uri: lb://user # 路由地址(匹配成功后的服务地址) user是用户服务的服务名称 order: 1 # 路由优先级,默认0,越低优先级越高 predicates: - Path=/user/** # 断言,匹配规则
If you don't use the routes automatically generated by nacos and define them yourself, then we
localhost:8083/user/findById
can normally access the resourcesuser
under the service when we access them/user/findById
.C:\Users\Admin>curl http://localhost:8083/user/findById?id=1 Zhangsan
Both methods can be used, depending on the actual situation of the project. locator.enabled: true
As long as it is configured in the gateway, when you perform gateway routing, the first directory in the request address must be the service name .