Spring Cloud(3):Ribbon的使用

基於搭建好的Eureka Server+Eureka Client:http://www.javashuo.com/article/p-pxvayqiy-mx.htmlhtml

有了服務,那麼如今學習如何調用服務java

上文搭建的是商品服務,如下搭建訂單服務,訂單服務調用商品服務web

 

對Eureka Client進行改造,方便之後獲得數據來源spring

在商品服務的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端口api

啓動三個商品服務,一個項目8771端口,一個8772端口,一個8773端口:app

多實例啓動方法以下圖負載均衡

 

新建一個SpringBoot項目order-service:dom

Web模塊必須的,因爲訂單服務自己也是服務須要Eureka,最後負載均衡調用Ribbonide

 

訂單服務開發(模擬實現):

實體類

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

 注意:服務名的一致,好比區分"_"和"-"

 

一般狀況下,不須要改變策略,輪詢策略爲最佳

可是若是有一個好機器,一堆差機器,那麼能夠調整好機器的權重

相關文章
相關標籤/搜索