基於搭建好的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
注意:服務名的一致,好比區分"_"和"-"
一般狀況下,不須要改變策略,輪詢策略爲最佳
可是若是有一個好機器,一堆差機器,那麼能夠調整好機器的權重