Soul网关源码分析(第五部分):如何与Spring Cloud服务进行集成
目标
-
使用 soul 接入 sprinngcloud 服务
-
源码解析 - springCloud 服务注册到网关
-
源码解析 - 网关代理 springCloud 服务
-
总结
一、接入 sprinngCloud 应用
本小节,我们参考《Soul 文档 —— springcloud 用户》文章,接入 Soul 服务网关。整个示例架构如下图所示:
下面,我们来开始正式接入 Spring Cloud 应用。
1.1 设置 springcloud 插件
使用浏览器,访问 soul-admin后台,进入「系统管理 -> 插件管理」,设置 springCloud 插件为开启
该插件是用来将 http协议
转成 springCloud协议
的核心。
1.2 启动 Nacos 服务
本文使用 nacos 作为注册中心,后续网关将从 nacos 上获取 springCloud 服务信息。
启动后使用浏览器,访问 nacos后台,进入「服务管理 -> 服务列表」,可以看到当前无服务注册进来。
1.3 网关引入 springCloud 的插件支持
1)依赖引入
修改 pom.xml
文件:
-
引入 soul-spring-boot-starter-plugin-springcloud 依赖,集成 springcloud 插件以访问 Spring Cloud 服务
-
引入 spring-cloud-starter-alibaba-nacos-discovery 依赖,集成 Nacos 作为 Spring Cloud 的注册中心
<!--soul springCloud plugin starter start-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-springcloud</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<!--soul springCloud plugin starter end-->
<!-- springCloud if you config register center is nacos please dependency this-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<!-- springCloud if you config register center is eureka please dependency end-->
2)配置引入
修改 application.yml
配置文件:
- 引入
spring.cloud.nacos.discovery.server-addr
配置,配置 Nacos 注册中心的地址 - 引入
soul.sync.websocket.urls
配置,配置数据同步策略
3)启动服务网关
IDEA 中执行 SoulBootstrapApplication 启动服务网关。
1.4 springCloud 服务接入网关
1)依赖引入
- 引入 springcloud starter 依赖
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-client-springcloud</artifactId>
<version>${last.version}</version>
</dependency>
2)配置引入
确认注册中心配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
新增 soul.springcloud 配置,配置项对应 SoulSpringCloudConfig 配置类。
soul:
springcloud:
admin-url: http://localhost:9095
context-path: /springcloud
full: true
# adminUrl: 为你启动的soul-admin 项目的ip + 端口,注意要加http://
# contextPath: 为你的这个mvc项目在soul网关的路由前缀,这个你应该懂意思把? 比如/order ,/product 等等,网关会根据你的这个前缀来进行路由.
# full: 设置true 代表代理你的整个服务,false表示代理你其中某几个controller
3)服务注册
需要在 Controller 的 HTTP API 方法上,添加 @SoulClient
注解,用于设置每个 API 方法对应的请求路径。代码如下:
@RestController
@RequestMapping("/test")
@SoulSpringCloudClient(path = "/test/**")
public class TestController {
@PostMapping("/save")
public UserDTO post(@RequestBody final UserDTO userDTO) {
userDTO.setUserName("hello world spring cloud save user");
return userDTO;
}
@GetMapping("/findByUserId")
public UserDTO findByUserId(@RequestParam("userId") final String userId) {
UserDTO userDTO = new UserDTO();
userDTO.setUserId(userId);
userDTO.setUserName("hello world spring cloud findBy user");
return userDTO;
}
}
在 Spring Cloud 应用启动时,Soul Client 会自动解析@SoulClient
注解的 API 方法,写入方法的元数据到 Soul Admin 控制台,最终通知到 Soul Bootstrap 服务网关。
4)服务启动
启动 springcloud 服务,输出日志 springCloud client register success
,接口元数据成功注册到 soul-admin
执行 DemoApplication 启动 Spring Cloud 应用。在 IDEA 控制台可以看到如下日志,看到写入 HTTP API 方法的元数据到 Soul Admin 控制台。
2021-01-20 01:57:18.513 INFO 3394 --- [pool-1-thread-1] o.d.s.client.common.utils.RegisterUtils : springCloud client register success: {"appName":"springCloud-test","context":"/springcloud","path":"/springcloud/order/save","pathDesc":"","rpcType":"springCloud","ruleName":"/springcloud/order/save","enabled":true}
2021-01-20 01:57:18.530 INFO 3394 --- [pool-1-thread-1] o.d.s.client.common.utils.RegisterUtils : springCloud client register success: {"appName":"springCloud-test","context":"/springcloud","path":"/springcloud/order/path/**","pathDesc":"","rpcType":"springCloud","ruleName":"/springcloud/order/path/**","enabled":true}
2021-01-20 01:57:18.543 INFO 3394 --- [pool-1-thread-1] o.d.s.client.common.utils.RegisterUtils : springCloud client register success: {"appName":"springCloud-test","context":"/springcloud","path":"/springcloud/order/findById","pathDesc":"","rpcType":"springCloud","ruleName":"/springcloud/order/findById","enabled":true}
2021-01-20 01:57:18.553 INFO 3394 --- [pool-1-thread-1] o.d.s.client.common.utils.RegisterUtils : springCloud client register success: {"appName":"springCloud-test","context":"/springcloud","path":"/springcloud/order/path/**/name","pathDesc":"","rpcType":"springCloud","ruleName":"/springcloud/order/path/**/name","enabled":true}
2021-01-20 01:57:18.564 INFO 3394 --- [pool-1-thread-1] o.d.s.client.common.utils.RegisterUtils : springCloud client register success: {"appName":"springCloud-test","context":"/springcloud","path":"/springcloud/test/**","pathDesc":"","rpcType":"springCloud","ruleName":"/springcloud/test/**","enabled":true}
使用浏览器,访问 soul-admin后台,进入「系统管理 -> 元数据」菜单,可以看到上述注册的元数据。如下图所示:
使用浏览器,访问 soul-admin后台,进入「插件列表 -> springCloud」菜单,可以看到选择器和规则。如下图所示:
1.5 接口测试
使用 Postman 模拟请求,访问 /test/findByUserId 接口,如下图所示:
使用 Postman 模拟请求,访问网关 /springcloud/test/findByUserId 接口,如下图所示:
二、源码解析
2.1 springCloud 服务注册到网关
springcloud 依赖 soul-spring-boot-starter-client-springcloud 接入到网关,看看做了哪些工作。
先看 SoulSpringCloudClientConfiguration
@Configuration
public class SoulSpringCloudClientConfiguration {
@Bean
public SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {...}
@Bean
public ContextRegisterListener contextRegisterListener(final SoulSpringCloudConfig soulSpringCloudConfig, final Environment env) {...}
@Bean
@ConfigurationProperties(prefix = "soul.springcloud")
public SoulSpringCloudConfig soulSpringCloudConfig() {...}
}
其负责创建 SpringCloudClientBeanPostProcessor 和 ContextRegisterListener 交给 spring 管理。
SpringCloudClientBeanPostProcessor 很明显是个后置处理类,其核心处理如下:
# SpringCloudClientBeanPostProcessor
@Override
public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName) throws BeansException {
//... only core logic
final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(bean.getClass());
for (Method method : methods) {
SoulSpringCloudClient soulSpringCloudClient = AnnotationUtils.findAnnotation(method, SoulSpringCloudClient.class);
executorService.execute(() -> RegisterUtils.doRegister(metaData, url, RpcTypeEnum.SPRING_CLOUD));
}
//...
}
主要负责筛选带有 @SoulSpringCloudClient 的 class 和 method,据此组织接口元数据,然后借助 RegisterUtils 注册到 soul-admin。
ContextRegisterListener 实现了 ApplicationListener,核心处理如下:
@Override
public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
if (!registered.compareAndSet(false, true)) {
return;
}
if (config.isFull()) {
RegisterUtils.doRegister(buildJsonParams(), url, RpcTypeEnum.SPRING_CLOUD);
}
}
监听到 contextRefreshedEvent 时,检查是否配置了全量注册,若是则注册元数据到 soul-admin。
即,springCloud 服务注册到 nacos,而其元数据则通过注册到 soul-admin,soul-bootstrap 从 soul-admin 同步数据后就可以进行相关服务的代理工作。
2.2 网关代理 springCloud 服务
未完待续…
上一篇: Soul的高性能网关搭建教程
下一篇: Soul"用户运营策略解析报告