zoukankan      html  css  js  c++  java
  • Spring Cloud(3):Ribbon的使用

    基于搭建好的Eureka Server+Eureka Client:https://www.cnblogs.com/xuyiqing/p/10861541.html

    有了服务,那么现在学习如何调用服务

    上文搭建的是商品服务,以下搭建订单服务,订单服务调用商品服务

    对Eureka Client进行改造,方便以后得到数据来源

    在商品服务的Controller层注入端口号,并进行回显:

    package org.dreamtech.product.controller;
    
    import org.dreamtech.product.domain.Product;
    import org.dreamtech.product.service.ProductService;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/api/product")
    public class ProductController {
    
        @Value("${server.port}")
        private String port;
    
        private final ProductService productService;
    
        @Autowired
        public ProductController(ProductService productService) {
            this.productService = productService;
        }
    
        @RequestMapping("/list")
        public Object list() {
            return productService.getProductList();
        }
    
        @RequestMapping("/find")
        public Object findById(@RequestParam("id") int id) {
            Product product = productService.findById(id);
            Product result = new Product();
            BeanUtils.copyProperties(product,result);
            result.setName(result.getName()+" data from port="+port);
            return result;
        }
    
    }

    启动Eureka Server,8761端口

    启动三个商品服务,一个项目8771端口,一个8772端口,一个8773端口:

    多实例启动方法如下图

    新建一个SpringBoot项目order-service:

    Web模块必须的,由于订单服务本身也是服务需要Eureka,最后负载均衡调用Ribbon

    订单服务开发(模拟实现):

    实体类

    package org.dreamtech.orderservice.domain;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class ProductOrder implements Serializable {
        //ID
        private int id;
        //商品名称
        private String productName;
        //订单号
        private String tradeNo;
        //价格
        private int price;
        //创建时间
        private Date createTime;
        //用户ID
        private int userId;
        //用户名
        private String userName;
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public int getUserId() {
            return userId;
        }
    
        public void setUserId(int userId) {
            this.userId = userId;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getProductName() {
            return productName;
        }
    
        public void setProductName(String productName) {
            this.productName = productName;
        }
    
        public String getTradeNo() {
            return tradeNo;
        }
    
        public void setTradeNo(String tradeNo) {
            this.tradeNo = tradeNo;
        }
    
        public int getPrice() {
            return price;
        }
    
        public void setPrice(int price) {
            this.price = price;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    }

    为了方便,和商品服务一样,不调用数据库,只做简单的模拟:

    在SpringBoot启动类中加入Bean

    package org.dreamtech.orderservice;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @SpringBootApplication
    public class OrderServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderServiceApplication.class, args);
        }
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }

    配置文件对端口和服务名称进行配置:

    server:
      port: 8781
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
    spring:
      application:
        name: order-service

    Controller:

    package org.dreamtech.orderservice.controller;
    
    import org.dreamtech.orderservice.service.ProductOrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/api/order")
    public class OrderController {
        private final ProductOrderService productOrderService;
    
        @Autowired
        public OrderController(ProductOrderService productOrderService) {
            this.productOrderService = productOrderService;
        }
    
        @RequestMapping("/save")
        public Object save(@RequestParam("user_id") int userId, @RequestParam("product_id") int productId) {
            return productOrderService.save(userId, productId);
        }
    }

    Service:

    package org.dreamtech.orderservice.service;
    
    import org.dreamtech.orderservice.domain.ProductOrder;
    
    public interface ProductOrderService {
        /**
         * 下单接口
         *
         * @param userId    用户ID
         * @param productId 商品ID
         * @return ProductOrder
         */
        ProductOrder save(int userId, int productId);
    }
    package org.dreamtech.orderservice.service.impl;
    
    import org.dreamtech.orderservice.domain.ProductOrder;
    import org.dreamtech.orderservice.service.ProductOrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.Date;
    import java.util.Map;
    import java.util.UUID;
    
    @Service
    public class ProductOrderServiceImpl implements ProductOrderService {
    
        private final RestTemplate restTemplate;
    
        @Autowired
        public ProductOrderServiceImpl(RestTemplate restTemplate) {
            this.restTemplate = restTemplate;
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public ProductOrder save(int userId, int productId) {
    
            Map<String, Object> productMap = restTemplate.getForObject("http://product-service/api/product/find?id=" + productId, Map.class);
    
            ProductOrder productOrder = new ProductOrder();
            productOrder.setCreateTime(new Date());
            productOrder.setUserId(userId);
            productOrder.setTradeNo(UUID.randomUUID().toString());
    
            if (productMap != null) {
                productOrder.setProductName(productMap.get("name").toString());
                productOrder.setPrice(Integer.parseInt(productMap.get("price").toString()));
            }
            return productOrder;
        }
    }

    注意:getForObject方法的url中product-service是我在商品服务中配置的名称

    启动项目,如果正常情况,Eureka应该显示如图:

    访问http://localhost:8781/api/order/save?user_id=1&product_id=2多次,我将多次的返回结果记录在下:

    {"id":0,"productName":"iPhone2 data from port=8771","tradeNo":"8beb0fe0-83ef-4d23-ae53-9399bac7eacc","price":2222,"createTime":"2019-05-15T03:21:12.432+0000","userId":1,"userName":null}
    {"id":0,"productName":"iPhone2 data from port=8773","tradeNo":"09544f1d-462b-413a-b14a-cc9d599bce39","price":2222,"createTime":"2019-05-15T03:21:48.467+0000","userId":1,"userName":null}
    {"id":0,"productName":"iPhone2 data from port=8771","tradeNo":"543e83a7-3e58-48bb-8aba-bd7635a10131","price":2222,"createTime":"2019-05-15T03:21:57.244+0000","userId":1,"userName":null}
    {"id":0,"productName":"iPhone2 data from port=8772","tradeNo":"b30bbd40-49e8-4001-917a-0ae36b172463","price":2222,"createTime":"2019-05-15T03:22:06.509+0000","userId":1,"userName":null}

    可以观察到,我开启了三个商品服务,这里自动在三个服务中进行了负载均衡,8771-8773随机访问

    在SpringBoot启动类中加入Bean是一种方式,还有另一种调用方式:

    不过还是推荐第一种

    package org.dreamtech.orderservice.service.impl;
    
    import org.dreamtech.orderservice.domain.ProductOrder;
    import org.dreamtech.orderservice.service.ProductOrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.Date;
    import java.util.Map;
    import java.util.UUID;
    
    @Service
    public class ProductOrderServiceImpl implements ProductOrderService {
        private final LoadBalancerClient loadBalancer;
    
        @Autowired
        public ProductOrderServiceImpl(, LoadBalancerClient loadBalancer) {
            this.loadBalancer = loadBalancer;
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public ProductOrder save(int userId, int productId) {
    
            ServiceInstance instance = loadBalancer.choose("product-service");
            String url = String.format("http://%s:%s/api/product/find?id="+productId,instance.getHost(),instance.getPort());
            RestTemplate restTemplate = new RestTemplate();
            Map<String, Object> productMap = restTemplate.getForObject(url, Map.class);
    
    
            ProductOrder productOrder = new ProductOrder();
            productOrder.setCreateTime(new Date());
            productOrder.setUserId(userId);
            productOrder.setTradeNo(UUID.randomUUID().toString());
    
            if (productMap != null) {
                productOrder.setProductName(productMap.get("name").toString());
                productOrder.setPrice(Integer.parseInt(productMap.get("price").toString()));
            }
            return productOrder;
        }
    }

    自定义负载均衡策略:

    Ribbon默认是轮询策略

    比如我想要使用随机策略,配置如下:

    product-service:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

     注意:服务名的一致,比如区分"_"和"-"

    通常情况下,不需要改变策略,轮询策略为最佳

    但是如果有一个好机器,一堆差机器,那么可以调整好机器的权重

  • 相关阅读:
    .Net WebClient 上传文件错误集锦
    Asp.net 1.1 Treeview 控件的绑定
    SQL Server 2008使用问题集锦
    14 个经典的javascript代码
    C#3.0之自动属性&对象初始化器
    Asp.Net Ajax 2.0 调用WebService 中的方法
    Access Insert Into 语法错误 集锦(不断更新中...)
    项目中常用的几个JS
    广州火车站网上订票系统2011年春运订票指南
    好文收集
  • 原文地址:https://www.cnblogs.com/xuyiqing/p/10867739.html
Copyright © 2011-2022 走看看