作者:踏風彡
來源:blog.csdn.net/qq_54217349/article/details/127955490
不管任何分布式的架構,它都離不開服務之間的拆分,細化,微服務也一樣,下面,風哥來帶大家一起了解一下微服務的服務拆分原則,并帶大家通過一個小案例了解一下服務間拆分和遠端調用吧。
1 服務拆分
1.1 服務拆分原則
開頭,風哥不墨叽了,把幾個微服務之間的拆分原則先告訴大家。
- 不同微服務之間,盡量不要有相同的業務,確定低耦合性
- 每個微服務都應該有一個屬于自己的獨立資料庫
- 各個微服務之間,可通過微服務對外暴露的業務接口進行通路
1.2 服務拆分示例
1.2.1 執行個體的demo的結構如下:
請忽略eureka,它是下個章節的内容,學習的時候,做這個案例,一不小心沒停下來。
cloud-demo:父工程
- order-service:訂單微服務,負責訂單相關業務(當然這裡隻是一個小demo,隻搞了一個查詢的功能)
- user-service:使用者微服務,負責使用者相關業務(功能也略少哈)
那麼,根據上邊服務拆分原則,可以得到如下結論(ps:沒看下面的小夥伴們可以先看下上邊,機靈的小腦袋瓜裡先思考一下有什麼結論):
- 使用者服務和訂單服務都必須對外暴露Restful接口,供其他微服務調用
- 兩個服務之間如果要調用另一個微服務的功能,隻能通過Restful接口調用,不能直接通路其他微服務的資料庫
- 是以,使用者微服務和訂單微服務要有自己獨立的資料庫
1.2.2 資料庫表結構
Eg: cloud-order表中含有cloud-user的id字段。
那個,導入工程啥的,在這我就不給具體流程了,大家學到了這裡,相信都有這些基本能力了,接下來咱們直接根據這個示範服務拆分的小demo,來聊一下遠端調用。
2 遠端調用
2.1 遠端調用執行個體
在這裡為了示範微服務間的遠端調用,在這裡就要設定需求場景了,先看原來demo的功能:
先看一下兩個微服務間需要互動的功能接口,這裡的小demo隻有一個,那就是查詢訂單的接口
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public Order queryOrderById(Long orderId) {
// 1.查詢訂單
Order order = orderMapper.findById(orderId);
return order;
}
}
接下來啟動服務,咱們看一下控制台傳回的資料
從上面,可以很清晰地看到user是空的,那麼我們查詢訂單的時候想讓它顯示對應的user資訊怎麼辦呢?
這個時候,訂單查詢子產品的接口就需要遠端調用user子產品的查詢接口得到相應的user資訊了。
那麼,不同子產品之間的怎麼調用其他子產品的接口呢?
有了這些疑問,接下來,大家跟着風哥一起探索一下吧。
2.2 案例需求
在做一個功能時,我們的大體思路都是先确定需求,畫好流程圖,然後讨論,明确需求,再去實施,微服務同樣也不例外。
接下來,咱們看一下各個子產品互相間的功能需求圖,咱們這個小demo及其簡單,微服務間的接口間的互相調用隻有order-service中的查詢接口的方法内去調用user-service中的查詢接口,來,看需求圖。
看了需求圖,相信大家對過程有了一個更清晰的了解,也明白接下來咱們需要做什麼了,沒錯,我上句話已經說過了,order-service子產品中的查詢方法要向user-service子產品發送一個http請求,調用http://localhost:8081/user/{userId}這個接口,獲得相應的使用者資訊。
然而呢,比較細心的小夥伴們,相信已經發現了現在風哥好像還沒有說通過調用使用者子產品查詢接口擷取使用者資料傳回的資料類型是什麼?有的人肯定會說,那肯定是User類型啊。
這樣說沒錯,但是說明咱們欠缺了思考,從另一個子產品的接口獲得資料,你這個子產品裡又沒有相應的資料類型,你怎麼将人家的資料封裝成User類型呢?而這也恰恰是咱們需要學習遠端調用中的一個關鍵部分。帶着疑問出發學習更有勁,那麼,跟着風哥來看一下具體的步驟吧。
大概步驟:
- 注冊一個RestTemplate的執行個體并注入到Spring容器中取
- 在order-service中修改OrderService類中的queryOrderById方法,根據Order對象中的userid查詢user資料
- 在OrderService類中注入RestTemplate的執行個體對象,通過調用它的getForObject()方法将指定url的資料封裝成指定類型的資料
- 将封裝的User對象加入到Order對象中去,傳回Order對象
來,小夥伴們跟着風哥的步驟一起來做一下,let’s go.
步驟一 在order子產品的啟動類注冊RestTemplate對象
為什麼選擇在order子產品的啟動類中呢,因為在這個過程中,order子產品的相應方法是一個消費者行為,user子產品充當的是一個服務者行為,而關于消費者和服務者理論,我會放在文末進行描述。
牛逼啊!接私活必備的 N 個開源項目!趕快收藏
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
/**
* 為了實作負載均衡
* 建立RestTemplate并注入Spring容器中
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
步驟二 調用相應接口擷取并封裝資料
在這裡,我把細分的2-4步合并為了一步,因為實作起來,不要問:風哥,為啥呢?因為它倆密不可分呐,拆開來描述是為了讓大家更清晰地去了解具體流程,而現在實作則要根據實際情況啊,寶貝兒們。
這裡我為什麼url前面用的是userservice,而不是其微服務子產品對應的端口呢,這就涉及了Eureka的知識了,在這裡沒改是為了給大家先埋下個種子,讓大家充滿幹勁去看本專欄下篇文章
restTemplate.getForObject(url, User.class):通過url調用相應的接口擷取資料并封裝成User資料類型
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查詢訂單
Order order = orderMapper.findById(orderId);
//2.查詢user
//2.1.擷取url位址
String url = "http://userservice/user/"+order.getUserId();
//2.2.根據url發起遠端調用擷取user
User user = restTemplate.getForObject(url, User.class);
//3.設定使用者
order.setUser(user);
// 4.傳回
return order;
}
}
最後傳回所需要的order資料類型即可。
結果圖
2.3 服務者和消費者
前面說好的哈,文末跟大家聊一聊服務者和消費者理論。
在服務調用關系中,都有兩個不同的角色:
- 服務者:即服務的提供方,說的現實一點,就是乙方啊
- 消費者:調用服務的一方,也說現實一點,就是甲方啊
在咱們這個小案例demo中,服務者和消費者非常清晰。
但是,凡是沒有絕對,就像相對靜止狀态一樣,狀态随時可能會變,可能下一個業務中user-service就成了消費方,而order就成了服務者了,是以,這要根據具體業務具體分析。