Soul源码阅读系列(七)Spring Cloud插件

本篇文章主要介绍学习使用Spring Cloud插件,如何将Spring Cloud服务接入到Soul网关。主要内容如下:

  • Soul中使用Spring Cloud服务

    • 查看官方样例
    • 引入依赖
    • 注册Spring Cloud服务
    • 运行Spring Cloud服务
    • 启动Soul AdminSoul Bootstrap
    • 体验Spring Cloud服务
  • SpringCloudPlugin 源码解析

在前面几篇文章中,已经体验过了Souldivide插件,apache dubbo插件和sofa插件,今天的Spring Cloud插件大体逻辑和之前的一致,接入和实现还会简单一些。

1. 在Soul中使用spring cloud服务

1.1 查看官方样例

Soul官方在soul-examples模块提供了测试样例,其中的soul-examples-springcloud模块演示的是Soul网关对springcloud服务的支持。模块目录及配置信息如下:

1

有关的配置信息还是和之前一样。在本项目中Spring Cloud的注册中心使用的是nacos

nacos可以在官网直接下载,然后解压,在bin目录下使用命令startup.cmd -m standalone就能启动成功。


server:
  port: 8884
  address: 0.0.0.0

spring:
  application:
    name: springCloud-test
  cloud: 
    nacos:
      discovery:
          server-addr: 127.0.0.1:8848 # 注册中心nacos的地址


springCloud-test:
  ribbon.NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

soul:
  springcloud:
    admin-url: http://localhost:9095 # soul-admin的地址
    context-path: /springcloud

logging:
  level:
    root: info
    org.dromara.soul: debug
  path: "./logs"
1.2 引入依赖

spring cloud服务的pom文件中引入soul相关依赖,当前版本是2.2.1

	  <dependency>
            <groupId>org.dromara</groupId>
            <artifactId>soul-spring-boot-starter-client-springcloud</artifactId>
            <version>${soul.version}</version>
        </dependency>

	<!--使用nacos作为注册中心-->
       <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
1.3 注册spring cloud服务

在需要被代理的接口上使用注解@SoulSpringCloudClient@SoulSpringCloudClient注解会把当前接口注册到soul网关中。使用方式如下:

1

如果其他接口也想被网关代理,使用方式是一样的。在@SoulSpringCloudClient注解中,指定path即可。

1.4 运行spring cloud服务

运行SoulTestSpringCloudApplication,启动soul-examples-springcloud项目。成功启动后,可以在控制台看见接口被成功注册到soul网关中。

1

1.5 启动Soul AdminSoul Bootstrap

参考之前的文章,启动Soul AdminSoul BootstrapSoul的后台界面如下:

1

如果spring cloud插件没有开启,需要手动在管理界面开启一下。

1

Soul Bootstrap中,加入相关依赖:

         <dependency>
            <groupId>org.dromara</groupId>
            <artifactId>soul-spring-boot-starter-plugin-httpclient</artifactId>
            <version>${project.version}</version>
        </dependency>
	 <!--soul springCloud plugin 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 start end-->

httpclient插件也是需要的,在soul网关将http协议转换为spring cloud协议后,还需要通过httpclient插件发起web mvc请求。

提一句,当spring cloud服务和soul-bootstrap等启动成功后,可以在注册中心看到这两个服务实例。

1

1.6 体验spring cloud服务

三个系统(本身的业务系统(这里就是soul-examples-sofa),Soul后台管理系统Soul Admin,Soul核心网关Soul Bootstrap)都启动成功后,就能够体验到sofa服务在网关soul中的接入。

  • 先直连spring cloud服务

1

  • 再通过Soul网关请求spring cloud服务

1

	 //实际spring cloud提供的服务
    @GetMapping("/findById")
    @SoulSpringCloudClient(path = "/findById")
    public OrderDTO findById(@RequestParam("id") final String id) {
        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setId(id);
        orderDTO.setName("hello world spring cloud findById");
        return orderDTO;
    }

上面演示的是先通过请求http://localhost:8884/order/findById?id=99直连spring cloud服务。再通过Soul网关发起请求http://localhost:9195/springcloud/order/findById?id=99,实际被调用的是spring cloud的服务。

SpringCloudPlugin 源码解析

// org.dromara.soul.plugin.springcloud.SpringCloudPlugin#doExecute    
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
       //是否匹配上规则    
       if (Objects.isNull(rule)) {
            return Mono.empty();
        }
        final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
        assert soulContext != null;
    //从缓存中获取选择器和规则信息
        final SpringCloudRuleHandle ruleHandle = SpringCloudRuleHandleCache.getInstance().obtainHandle(SpringCloudPluginDataHandler.getRuleCacheKey(rule));
        final SpringCloudSelectorHandle selectorHandle = SpringCloudSelectorHandleCache.getInstance().obtainHandle(selector.getId());
        if (StringUtils.isBlank(selectorHandle.getServiceId()) || StringUtils.isBlank(ruleHandle.getPath())) {
            Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_CONFIG_SPRINGCLOUD_SERVICEID.getCode(), SoulResultEnum.CANNOT_CONFIG_SPRINGCLOUD_SERVICEID.getMsg(), null);
            return WebFluxResultUtils.result(exchange, error);
        }

    // 负载均衡选择实例
        final ServiceInstance serviceInstance = loadBalancer.choose(selectorHandle.getServiceId());
        if (Objects.isNull(serviceInstance)) {
            Object error = SoulResultWrap.error(SoulResultEnum.SPRINGCLOUD_SERVICEID_IS_ERROR.getCode(), SoulResultEnum.SPRINGCLOUD_SERVICEID_IS_ERROR.getMsg(), null);
            return WebFluxResultUtils.result(exchange, error);
        }
    //构建请求url
        final URI uri = loadBalancer.reconstructURI(serviceInstance, URI.create(soulContext.getRealUrl()));

        String realURL = buildRealURL(uri.toASCIIString(), soulContext.getHttpMethod(), exchange.getRequest().getURI().getQuery());

    //设置请求信息
        exchange.getAttributes().put(Constants.HTTP_URL, realURL);
        //set time out.
        exchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());
    //处理下一个插件   
    return chain.execute(exchange);
    }

Spring Cloud构建的微服务是支持RESTful,可以通过http请求发起调用。

SpringCloudPlugin中设置好请求信息后,就交给后续的插件处理的,是需要要开启divide插件。

小结,这篇文章主要介绍了Soulspring cloud提供的支持,结合实际案例进行了演示,简单跟读了下源码。