微服务如何进行远程调用其他服务

前置知识:将本地服务注册到nacos地址上:

1、服务调用:

现在我们需要使用service-order 服务调用sercice-business服务

使用@EnableDiscoveryClient注解, 开启服务调用

引入依赖

XML 复制代码
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

需要被调用的服务启动类:

java 复制代码
@EnableDiscoveryClient //开启服务调用
@SpringBootApplication
public class BusinessMainApplication{
    public static void main(String[] args) {
        SpringApplication.run(BusinessMainApplication.class,args);
    }
}

编写需要进行调用的接口:

java 复制代码
    @GetMapping("/business/{id}")
    public Business getById(@PathVariable("id") String id){
        return  businessService.getBusiness(id);
    }

创建RestTemplate配置类,防止new 多个对象

java 复制代码
@Configuration
public class OrderConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

在服务层进行调用另外一个服务

java 复制代码
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private RestTemplate restTemplate;


    @Override
    public Order getById(Long id) {
        Order order = new Order();
        order.setTotalAmount(new BigDecimal("1000"));
        order.setNickName("尚硅谷");
        order.setId(id);
        order.setProductList(Lists.newArrayList());
        return order;
    }

    @Override
    public Order createOrder(Long userId, Long productId) {
        //进行远程调用获取商品数据
        Business businessById = getBusinessById(productId.toString());

        Order order = new Order();
        order.setId(1L);
        order.setAddress("将军大道108号");
        order.setTotalAmount(BigDecimal.valueOf(businessById.getPrice() * businessById.getCount()));
        order.setNickName("尚硅谷");
        order.setUserId(userId);
        order.setProductList(Arrays.asList(businessById));
        return order;
    }

    /**
     * 手动选择需要的实例进行调用
     * @param businessId
     * @return
     */
    public Business getBusinessById(String businessId){
        List<ServiceInstance> instances = discoveryClient.getInstances("service-business");

        //获取服务的第几个实例对象
        ServiceInstance instance = instances.get(0);
        //端口的URL
        String url = "http://" + instance.getHost() + ":"  + instance.getPort() + "/business/" + businessId;

        log.info("远程调用的URL:" + url);

        //进行远程调用
        Business forObject = restTemplate.getForObject(url, Business.class);
        log.info("返回的数据:" + forObject.toString());
        return forObject;
    }

}

2、负载均衡:

如果被调用的服务有多个实例,现在我们为了减轻某个服务的压力,对服务进行轮询调用:

现在我们需要在调用方,使用loadBanlancer依赖

依赖引入:

XML 复制代码
  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

依赖导入:

java 复制代码
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Override
    public Order getById(Long id) {
        Order order = new Order();
        order.setTotalAmount(new BigDecimal("1000"));
        order.setNickName("尚硅谷");
        order.setId(id);
        order.setProductList(Lists.newArrayList());
        return order;
    }

    @Override
    public Order createOrder(Long userId, Long productId) {
        //进行远程调用获取商品数据
//        Business businessById = getBusinessById(productId.toString());
//        Business businessById = getBusinessByIdWithLoadBalancer(productId.toString());
        Business businessById = getBusinessByIdWithAnnotation(productId.toString());

        Order order = new Order();
        order.setId(1L);
        order.setAddress("将军大道108号");
        order.setTotalAmount(BigDecimal.valueOf(businessById.getPrice() * businessById.getCount()));
        order.setNickName("尚硅谷");
        order.setUserId(userId);
        order.setProductList(Arrays.asList(businessById));
        return order;
    }

    /**
     * 手动选择需要的实例进行调用
     * @param businessId
     * @return
     */
    public Business getBusinessById(String businessId){
        List<ServiceInstance> instances = discoveryClient.getInstances("service-business");

        //获取服务的第几个实例对象
        ServiceInstance instance = instances.get(0);
        //端口的URL
        String url = "http://" + instance.getHost() + ":"  + instance.getPort() + "/business/" + businessId;

        log.info("远程调用的URL:" + url);

        //进行远程调用
        Business forObject = restTemplate.getForObject(url, Business.class);
        log.info("返回的数据:" + forObject.toString());
        return forObject;
    }


    /**
     * 使用LoadBalancer进行负载均衡
     * @param businessId
     * @return
     */
    public Business getBusinessByIdWithLoadBalancer(String businessId){

        ServiceInstance choose = loadBalancerClient.choose("service-business");
        //端口的URL
        String url = "http://" + choose.getHost() + ":"  + choose.getPort() + "/business/" + businessId;

        log.info("IP:" + choose.getHost() + ":" + choose.getPort());
        log.info("远程调用的URL:" + url);

        //进行远程调用
        Business forObject = restTemplate.getForObject(url, Business.class);
        log.info("返回的数据:" + forObject.toString());
        return forObject;
    }


    /**
     * 使用注解@LoadBalancer进行负载均衡
     * 需要在restTemplate上添加注解LoadBalancer
     * @param businessId
     * @return
     */
    public Business getBusinessByIdWithAnnotation(String businessId){

        String url = "http://service-business/business/" + businessId;


        //进行远程调用
        Business forObject = restTemplate.getForObject(url, Business.class);
        log.info("返回的数据:" + forObject.toString());
        return forObject;
    }


}

其中,第三种,使用注解的方式进行负载均衡,需要将注解添加在restTemplate配置类上

java 复制代码
@Configuration
public class OrderConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
相关推荐
橙淮1 小时前
并发编程(六)
java·jvm
千里马学框架1 小时前
aosp新增窗口层级 Type 完整实现方案(有源码)-wms需求和面试题
android·智能手机·架构·wms·aaos·车机
拽着尾巴的鱼儿1 小时前
springboot openfeign 自定义feign 接口重试机制
java·spring boot·后端
白露与泡影1 小时前
2026大厂Java面试题大全!牛客网最新版
java·开发语言
EntyIU2 小时前
JVM内存与GC笔记
java·jvm·笔记
AI_Auto2 小时前
【智能制造】- APS系列|14 生产计划三层架构:长期、中期、短期
架构·制造
XS0301062 小时前
并发编程 六
java·后端
yaoxin5211232 小时前
419. 现代 Java IO 最佳实践 - 写入文本文件
java·windows·python
雪宫街道2 小时前
synchronized 锁的范围:对象锁、类锁与代码块锁
java·jvm·后端·面试
morning_judger2 小时前
Agent系列(一) - Agent系统分层架构
人工智能·架构