上一篇寫了經過Ribbon進行服務調用,這篇其它都同樣,惟一不同的就是經過Feign進行服務調用。html
註冊中心和商品微服務不變,和上篇博客同樣,具體參考:SpringCloud(4)---Ribbon服務調用,源碼分析git
這邊只重寫訂單微服務。github
項目代碼GitHub地址:https://github.com/yudiandemingzi/spring-cloud-studyspring
這裏相對於上一篇的訂單微服務只要新添加一個jar包編程
<!--feign依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
server: port: 9001 #指定註冊中心地址 eureka: client: serviceUrl: defaultZone: http://localhost:7001/eureka/ #服務的名稱 spring: application: name: order-service #自定義負載均衡策略(通常不用配用默認的) product-service: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
@SpringBootApplication //添加@EnableFeignClients註解 @EnableFeignClients public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
訂單實體類和訂單接口這裏就不寫類,和上篇同樣json
@Service public class ProductOrderServiceImpl implements ProductOrderService { @Autowired private ProductClient productClient; @Override public ProductOrder save(int userId, int productId) { //獲取json格式的字符串數據 String response = productClient.findById(productId); //Json字符串轉換成JsonNode對象 JsonNode jsonNode = JsonUtils.str2JsonNode(response); //將數據封裝到訂單實體中 ProductOrder productOrder = new ProductOrder(); productOrder.setCreateTime(new Date()); productOrder.setUserId(userId); productOrder.setTradeNo(UUID.randomUUID().toString()); //獲取商品名稱和商品價格 productOrder.setProductName(jsonNode.get("name").toString()); productOrder.setPrice(Integer.parseInt(jsonNode.get("price").toString())); //由於在商品微服務配置了集羣,因此這裏打印看下調用了是哪一個集羣節點,輸出端口號。 System.out.println(jsonNode.get("name").toString()); return productOrder; } }
能夠把這裏類理解成,就是你須要調用的微服務的controller層(這裏指商品微服務),這樣相對於Ribbon來說代碼的可讀性就高多了。api
/** * 商品服務客戶端 * name = "product-service"是服務端名稱 */ @FeignClient(name = "product-service") public interface ProductClient { //這樣組合就至關於http://product-service/api/v1/product/find @GetMapping("/api/v1/product/find") String findById(@RequestParam(value = "id") int id); }
/** * json工具類 */ public class JsonUtils { private static final ObjectMapper objectMappper = new ObjectMapper(); //json字符串轉JsonNode對象的方法 public static JsonNode str2JsonNode(String str){ try { return objectMappper.readTree(str); } catch (IOException e) { return null; } } }
@RestController @RequestMapping("api/v1/order") public class OrderController { @Autowired private ProductOrderService productOrderService; @RequestMapping("save") public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){ return productOrderService.save(userId, productId); } }
同時一樣它能夠達到負載均衡的效果。app
在使用Feign的時候,要注意使用requestBody,應該使用@PostMapping負載均衡
總到來講,Feign的源碼實現的過程以下:dom
(1)首先經過@EnableFeignCleints註解開啓FeignCleint
(2)根據Feign的規則實現接口,並加@FeignCleint註解
(3)程序啓動後,會進行包掃描,掃描全部的@ FeignCleint的註解的類,並將這些信息注入到ioc容器中。
(4)當接口的方法被調用,經過jdk的代理,來生成具體的RequesTemplate
(5)RequesTemplate在生成Request
(6)Request交給Client去處理,其中Client能夠是HttpUrlConnection、HttpClient也能夠是Okhttp
(7)最後Client被封裝到LoadBalanceClient類,這個類結合類Ribbon作到了負載均衡。
(1) feign自己裏面就包含有了ribbon,只是對於ribbon進行進一步封裝
(2) feign自身是一個聲明式的僞http客戶端,寫起來更加思路清晰和方便
(3) fegin是一個採用基於接口的註解的編程方式,更加簡便
最後推薦一篇對源碼解析不錯的博客:深刻理解Feign之源碼解析。
我只是偶爾安靜下來,對過去的種種思忖一番。那些曾經的舊時光裏即使有過天真愚鈍,也不值得譴責。畢竟,日後的日子,還很長。不斷鼓勵本身,
天一亮,又是嶄新的起點,又是未知的征程(上校7)