spring cloud中实现接口广播请求到服务提供者

一、背景

假如现在有一台服务A,两台服务B,可以简化为如下图模型:

 需求:一次请求服务A需要同时将请求广播打到两台服务B上。

二、实现方案

2.1 需要应用到两个类:

2.1.1:LoadBalancerClient
package org.springframework.cloud.client.loadbalancer;

import java.io.IOException;
import java.net.URI;
import org.springframework.cloud.client.ServiceInstance;

public interface LoadBalancerClient extends ServiceInstanceChooser {
    <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

    <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

    URI reconstructURI(ServiceInstance instance, URI original);
}

2.1.2:DiscoveryClient

package org.springframework.cloud.client.discovery;

import java.util.List;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.Ordered;

public interface DiscoveryClient extends Ordered {
    int DEFAULT_ORDER = 0;

    String description();

    List<ServiceInstance> getInstances(String serviceId);

    List<String> getServices();

    default void probe() {
        this.getServices();
    }

    default int getOrder() {
        return 0;
    }
}

以上两个类都是SpringCloud中的,读者自己可以搜索引入对应的包,这里就不写引入的包的配置文件了,因为笔者懒。

2.2 自定义核心实现

2.2.1:服务A中的Controller


@RestController
@RequestMapping("/v1/test_a")
public class TestController {

    @Resource
    private TestService testService;

    
    @getMapping(path = "/invidate")
    public Result<Boolean> test() {
        return Result.Builder.success(testService.test());
    }
}

2.2.2:服务A中的TestService(核心实现)

public void test(){
        String serviceId = "test_b";
        final List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        if (CollectionUtils.isNotEmpty(instances)) {
            for (ServiceInstance instance : instances) {
                try {
                    Server server = new Server(instance.getHost(), instance.getPort());
                    RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(instance.getServiceId(), server);
                    loadBalancerClient.execute(instance.getServiceId(), ribbonServer, v -> {
                        String host = instance.getHost();
                        int port = instance.getPort();
                        String url = "http://" + host + ":" + port + "/v1/test_b/invalidate";
                        url = String.format(url, req.getWbCode());
                        RestTemplate restTemplate = new RestTemplate();
                        return restTemplate.getForObject(url, Result.class);
                    });
                } catch (IOException e) {
                    log.error("loadBalancerClient happen error:{}", e.getMessage(), e);
                }
            }
        }
    }

代码中的serviceId=test_b,这个test_b是笔者nacos注册中心注册的服务的名称,笔者的服务是用nacos作为服务发现和注册中心的,如果读者的服务的发现和注册中心不一致,可以自己理解了原理后自己研究一下。

代码中的“/v1/test_b/invalidate”就是服务A需要请求的服务B中的接口。这个段代码的核心是先用组件discoveryClient获取到服务提供者的列表,然后遍历每个服务提供者,向每个服务提供者发送信息。

2.2.3 服务B中的Controller

@RestController
@RequestMapping("/v1/test_b")
public class InvalidCacheInnerController {

    @GetMapping(path = "/invalidate")
    public Result<Boolean> invalidate() {
        return Result.Builder.success(true);
    }
}

服务B中就是简单返回一个true就完事了。

化繁为简,大道至简~~~~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值