目标

  • 使用 soul 接入 sprinngcloud 服务
  • 源码解析 - springCloud 服务注册到网关
  • 源码解析 - 网关代理 springCloud 服务
  • 总结

一、接入 sprinngCloud 应用

本小节,我们参考《Soul 文档 —— springcloud 用户》文章,接入 Soul 服务网关。整个示例架构如下图所示:

Soul网关源码解析(五)接入spring cloud服务 - 图1

下面,我们来开始正式接入 Spring Cloud 应用。

1.1 设置 springcloud 插件

使用浏览器,访问 soul-admin后台,进入「系统管理 -> 插件管理」,设置 springCloud 插件为开启

Soul网关源码解析(五)接入spring cloud服务 - 图2

该插件是用来将 http协议 转成 springCloud协议 的核心。

1.2 启动 Nacos 服务

本文使用 nacos 作为注册中心,后续网关将从 nacos 上获取 springCloud 服务信息。

启动后使用浏览器,访问 nacos后台,进入「服务管理 -> 服务列表」,可以看到当前无服务注册进来。

Soul网关源码解析(五)接入spring cloud服务 - 图3

1.3 网关引入 springCloud 的插件支持

1)依赖引入

修改 pom.xml 文件:

  • 引入 soul-spring-boot-starter-plugin-springcloud 依赖,集成 springcloud 插件以访问 Spring Cloud 服务
  • 引入 spring-cloud-starter-alibaba-nacos-discovery 依赖,集成 Nacos 作为 Spring Cloud 的注册中心
  1. <!--soul springCloud plugin starter start-->
  2. <dependency>
  3. <groupId>org.dromara</groupId>
  4. <artifactId>soul-spring-boot-starter-plugin-springcloud</artifactId>
  5. <version>${project.version}</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.springframework.cloud</groupId>
  9. <artifactId>spring-cloud-commons</artifactId>
  10. <version>2.2.0.RELEASE</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework.cloud</groupId>
  14. <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  15. <version>2.2.0.RELEASE</version>
  16. </dependency>
  17. <!--soul springCloud plugin starter end-->
  18. <!-- springCloud if you config register center is nacos please dependency this-->
  19. <dependency>
  20. <groupId>com.alibaba.cloud</groupId>
  21. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  22. <version>2.1.0.RELEASE</version>
  23. </dependency>
  24. <!-- 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 配置,配置数据同步策略

Soul网关源码解析(五)接入spring cloud服务 - 图4

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网关源码解析(五)接入spring cloud服务 - 图5

使用浏览器,访问 soul-admin后台,进入「插件列表 -> springCloud」菜单,可以看到选择器和规则。如下图所示:

Soul网关源码解析(五)接入spring cloud服务 - 图6

1.5 接口测试

使用 Postman 模拟请求,访问 /test/findByUserId 接口,如下图所示:

Soul网关源码解析(五)接入spring cloud服务 - 图7

使用 Postman 模拟请求,访问网关 /springcloud/test/findByUserId 接口,如下图所示:

Soul网关源码解析(五)接入spring cloud服务 - 图8

二、源码解析

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 服务

未完待续…