官方網(wǎng)站:柏碼 - 讓每一行代碼都閃耀智慧的光芒! (itbaima.net)
p1:前言,走進微服務(wù)
注意:此階段學習推薦的電腦配置,至少配備4核心CPU(主頻3.0Ghz以上)+16GB內(nèi)存,否則卡到你懷疑人生。
前面我們講解了SpringBoot框架,通過使用SpringBoot框架,我們的項目開發(fā)速度可以說是得到了質(zhì)的提升。同時,我們對于項目的維護和理解,也會更加的輕松??梢?,SpringBoot為我們的開發(fā)帶來了巨大便捷。而這一部分,我們將基于SpringBoot,繼續(xù)深入到企業(yè)實際場景,探討微服務(wù)架構(gòu)下的SpringCloud。這個部分我們會更加注重于架構(gòu)設(shè)計上的講解,弱化實現(xiàn)原理方面的研究。
傳統(tǒng)項目轉(zhuǎn)型
要說近幾年最火熱的話題,那還得是微服務(wù),那么什么是微服務(wù)呢?
我們可以先從技術(shù)的演變開始看起,在我們學習JavaWeb之后,一般的網(wǎng)站開發(fā)模式為Servlet+JSP,但是實際上我們在學習了SSM之后,會發(fā)現(xiàn)這種模式已經(jīng)遠遠落后了,第一,一個公司不可能去招那么多同時會前端+后端的開發(fā)人員,就算招到,也并不一定能保證兩個方面都比較擅長,相比前后端分開學習的開發(fā)人員,顯然后者的學習成本更低,專注度更高。因此前后端分離成為了一種新的趨勢。通過使用SpringBoot,我們幾乎可以很快速地開發(fā)一個高性能的單體應(yīng)用,只需要啟動一個服務(wù)端,我們整個項目就開始運行了,各項功能融于一體,開發(fā)起來也更加輕松。
但是隨著我們項目的不斷擴大,單體應(yīng)用似乎顯得有點乏力了。
隨著越來越多的功能不斷地加入到一個SpringBoot項目中,隨著接口不斷增加,整個系統(tǒng)就要在同一時間內(nèi)響應(yīng)更多類型的請求,顯然,這種擴展方式是不可能無限使用下去的,總有一天,這個SpringBoot項目會龐大到運行緩慢。并且所有的功能如果都集成在單端上,那么所有的請求都會全部匯集到一臺服務(wù)器上,對此服務(wù)器造成巨大壓力。
可以試想一下,如果我們的電腦已經(jīng)升級到i9-12900K,但是依然在運行項目的時候緩慢,無法同一時間響應(yīng)成千上萬的請求,那么這個問題就已經(jīng)不是單純升級機器配置可以解決的了。
傳統(tǒng)單體架構(gòu)應(yīng)用隨著項目規(guī)模的擴大,實際上會暴露越來越多的問題,尤其是一臺服務(wù)器無法承受龐大的單體應(yīng)用部署,并且單體應(yīng)用的維護也會越來越困難,我們得尋找一種新的開發(fā)架構(gòu)來解決這些問題了。
Martin Fowler在2014年提出了“微服務(wù)”架構(gòu),它是一種全新的架構(gòu)風格。
- 微服務(wù)把一個龐大的單體應(yīng)用拆分為一個個的小型服務(wù),比如我們原來的圖書管理項目中,有登錄、注冊、添加、刪除、搜索等功能,那么我們可以將這些功能單獨做成一個個小型的SpringBoot項目,獨立運行。
- 每個小型的微服務(wù),都可以獨立部署和升級,這樣,就算整個系統(tǒng)崩潰,那么也只會影響一個服務(wù)的運行。
- 微服務(wù)之間使用HTTP進行數(shù)據(jù)交互,不再是單體應(yīng)用內(nèi)部交互了,雖然這樣會顯得更麻煩,但是帶來的好處也是很直接的,甚至能突破語言限制,使用不同的編程語言進行微服務(wù)開發(fā),只需要使用HTTP進行數(shù)據(jù)交互即可。
- 我們可以同時購買多臺主機來分別部署這些微服務(wù),這樣,單機的壓力就被分散到多臺機器,并且每臺機器的配置不一定需要太高,這樣就能節(jié)省大量的成本,同時安全性也得到很大的保證。
- 甚至同一個微服務(wù)可以同時存在多個,這樣當其中一個服務(wù)器出現(xiàn)問題時,其他服務(wù)器也在運行同樣的微服務(wù),這樣就可以保證一個微服務(wù)的高可用。
當然,這里只是簡單的演示一下微服務(wù)架構(gòu),實際開發(fā)中肯定是比這個復雜得多的。
可見,采用微服務(wù)架構(gòu),更加能夠應(yīng)對當今時代下的種種考驗,傳統(tǒng)項目的開發(fā)模式,需要進行架構(gòu)上的升級。
-------------------------------------------------------------------------------------------------------------------------
P2:認識SpringCloud
走進SpringCloud
前面我們介紹了微服務(wù)架構(gòu)的優(yōu)點,那么同樣的,這些優(yōu)點的背后也存在著諸多的問題:
- 要實現(xiàn)微服務(wù)并不是說只需要簡單地將項目進行拆分,我們還需要考慮對各個微服務(wù)進行管理、監(jiān)控等,這樣我們才能夠及時地尋找和排查問題。因此微服務(wù)往往需要的是一整套解決方案,包括服務(wù)注冊和發(fā)現(xiàn)、容災處理、負載均衡、配置管理等。
- 它不像單體架構(gòu)那種方便維護,由于部署在多個服務(wù)器,我們不得不去保證各個微服務(wù)能夠穩(wěn)定運行,在管理難度上肯定是高于傳統(tǒng)單體應(yīng)用的。
- 在分布式的環(huán)境下,單體應(yīng)用的某些功能可能會變得比較麻煩,比如分布式事務(wù)。
所以,為了更好地解決這些問題,SpringCloud正式登場。
SpringCloud是Spring提供的一套分布式解決方案,集合了一些大型互聯(lián)網(wǎng)公司的開源產(chǎn)品,包括諸多組件,共同組成SpringCloud框架。并且,它利用Spring Boot的開發(fā)便利性巧妙地簡化了分布式系統(tǒng)基礎(chǔ)設(shè)施的開發(fā),如服務(wù)發(fā)現(xiàn)注冊、配置中心、消息總線、負載均衡、熔斷機制、數(shù)據(jù)監(jiān)控等,都可以用Spring Boot的開發(fā)風格做到一鍵啟動和部署。
由于中小型公司沒有獨立開發(fā)自己的分布式基礎(chǔ)設(shè)施的能力,使用SpringCloud解決方案能夠以最低的成本應(yīng)對當前時代的業(yè)務(wù)發(fā)展。
可以看到,SpringCloud整體架構(gòu)的亮點是非常明顯的,分布式架構(gòu)下的各個場景,都有對應(yīng)的組件來處理,比如基于Netflix(奈飛)的開源分布式解決方案提供的組件:
- Eureka - 實現(xiàn)服務(wù)治理(服務(wù)注冊與發(fā)現(xiàn)),我們可以對所有的微服務(wù)進行集中管理,包括他們的運行狀態(tài)、信息等。
- Ribbon - 為服務(wù)之間相互調(diào)用提供負載均衡算法(現(xiàn)在被SpringCloudLoadBalancer取代)
- Hystrix - 斷路器,保護系統(tǒng),控制故障范圍。暫時可以跟家里電閘的保險絲類比,當觸電危險發(fā)生時能夠防止進一步的發(fā)展。
- Zuul - api網(wǎng)關(guān),路由,負載均衡等多種作用,就像我們的路由器,可能有很多個設(shè)備都連接了路由器,但是數(shù)據(jù)包要轉(zhuǎn)發(fā)給誰則是由路由器在進行(已經(jīng)被SpringCloudGateway取代)
- Config - 配置管理,可以實現(xiàn)配置文件集中管理
當然,這里只是進行簡單的了解即可,實際上微服務(wù)的玩法非常多,我們后面的學習中將會逐步進行探索。
那么首先,我們就從注冊中心開始說起。
-------------------------------------------------------------------------------------------------------------------------
p3:微服務(wù)項目搭建(一)
Eureka 注冊中心
官方文檔:Spring Cloud Netflix
小貼士:各位小伙伴在學習的過程中覺得有什么疑惑的可以直接查閱官方文檔,我們會在每一個技術(shù)開始之前貼上官方文檔的地址,方便各位進行查閱,同時在我們的課程中并不一定會完完整整地講完整個框架的內(nèi)容,有關(guān)詳細的功能和使用方法文檔中也是寫的非常清楚的,感興趣的可以深入學習哦。
微服務(wù)項目結(jié)構(gòu)
現(xiàn)在我們重新設(shè)計一下之前的圖書管理系統(tǒng)項目,將原有的大型(也許 項目進行拆分,注意項目拆分一定要盡可能保證單一職責,相同的業(yè)務(wù)不要在多個微服務(wù)中重復出現(xiàn),如果出現(xiàn)需要借助其他業(yè)務(wù)完成的服務(wù),那么可以使用服務(wù)之間相互調(diào)用的形式來實現(xiàn)(之后會介紹):
- 登錄驗證服務(wù):用于處理用戶注冊、登錄、密碼重置等,反正就是一切與賬戶相關(guān)的內(nèi)容,包括用戶信息獲取等。
- 圖書管理服務(wù):用于進行圖書添加、刪除、更新等操作,圖書管理相關(guān)的服務(wù),包括圖書的存儲等和信息獲取。
- 圖書借閱服務(wù):交互性比較強的服務(wù),需要和登陸驗證服務(wù)和圖書管理服務(wù)進行交互。
那么既然要將單體應(yīng)用拆分為多個小型服務(wù),我們就需要重新設(shè)計一下整個項目目錄結(jié)構(gòu),這里我們就創(chuàng)建多個子項目,每一個子項目都是一個服務(wù),這樣由父項目統(tǒng)一管理依賴,就無需每個子項目都去單獨管理依賴了,也更方便一點。
我們首先創(chuàng)建一個普通的SpringBoot項目:
然后不需要勾選任何依賴,直接創(chuàng)建即可,項目創(chuàng)建完成并初始化后,我們刪除父工程的無用文件,只保留必要文件,像下面這樣:
接著我們就可以按照我們劃分的服務(wù),進行子工程創(chuàng)建了,創(chuàng)建一個新的Maven項目,注意父項目要指定為我們一開始創(chuàng)建的的項目,子項目命名隨意:
子項目創(chuàng)建好之后,接著我們在子項目中創(chuàng)建SpringBoot的啟動主類:
接著我們點擊運行,即可啟動子項目了,實際上這個子項目就一個最簡單的SpringBoot web項目,注意啟動之后最下方有彈窗,我們點擊"使用 服務(wù)",這樣我們就可以實時查看當前整個大項目中有哪些微服務(wù)了:
接著我們以同樣的方法,創(chuàng)建其他的子項目,注意我們最好將其他子項目的端口設(shè)置得不一樣,不然會導致端口占用,我們分別為它們創(chuàng)建
application.yml
文件:
接著我們來嘗試啟動一下這三個服務(wù),正常情況下都是可以直接啟動的:
可以看到它們分別運行在不同的端口上,這樣,就方便不同的程序員編寫不同的服務(wù)了,提交當前項目代碼時的沖突率也會降低。
P4:微服務(wù)項目搭建(二)
接著我們來創(chuàng)建一下數(shù)據(jù)庫,這里還是老樣子,創(chuàng)建三個表即可,當然實際上每個微服務(wù)單獨使用一個數(shù)據(jù)庫服務(wù)器也是可以的,因為按照單一職責服務(wù)只會操作自己對應(yīng)的表,這里UP主比較窮,就只用一個數(shù)據(jù)庫演示了:
創(chuàng)建好之后,結(jié)果如下,一共三張表,各位可以自行添加一些數(shù)據(jù)到里面,這就不貼出來了:
接著我們來稍微寫一點業(yè)務(wù),比如用戶信息查詢業(yè)務(wù),我們先把數(shù)據(jù)庫相關(guān)的依賴進行導入,這里依然使用Mybatis框架,首先在父項目中添加MySQL驅(qū)動和Lombok依賴:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
由于不是所有的子項目都需要用到Mybatis,我們在父項目中只進行版本管理即可:
<dependencyManagement> <dependencies> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> </dependencies> </dependencyManagement>
接著我們就可以在用戶服務(wù)子項目中添加此依賴了:
<dependencies> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> </dependencies>
接著添加數(shù)據(jù)源信息(UP用到是阿里云的MySQL云數(shù)據(jù)庫,各位注意修改一下數(shù)據(jù)庫地址):
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://cloudstudy.mysql.cn-chengdu.rds.aliyuncs.com:3306/cloudstudy username: test password: 123456
接著我們來寫用戶查詢相關(guān)的業(yè)務(wù):
@Data public class User { int uid; String name; String sex; }
@Mapper public interface UserMapper { @Select("select * from DB_USER where uid = #{uid}") User getUserById(int uid); }
public interface UserService { User getUserById(int uid); }
@Service public class UserServiceImpl implements UserService { @Resource UserMapper mapper; @Override public User getUserById(int uid) { return mapper.getUserById(uid); } }
@RestController public class UserController { @Resource UserService service; //這里以RESTFul風格為例 @RequestMapping("/user/{uid}") public User findUserById(@PathVariable("uid") int uid){ return service.getUserById(uid); } }
現(xiàn)在我們訪問即可拿到數(shù)據(jù):
同樣的方式,我們完成一下圖書查詢業(yè)務(wù),注意現(xiàn)在是在圖書管理微服務(wù)中編寫(別忘了導入Mybatis依賴以及配置數(shù)據(jù)源):
@Data public class Book { int bid; String title; String desc; }
@Mapper public interface BookMapper { @Select("select * from DB_BOOK where bid = #{bid}") Book getBookById(int bid); }
public interface BookService { Book getBookById(int bid); }
@Service public class BookServiceImpl implements BookService { @Resource BookMapper mapper; @Override public Book getBookById(int bid) { return mapper.getBookById(bid); } }
@RestController public class BookController { @Resource BookService service; @RequestMapping("/book/{bid}") Book findBookById(@PathVariable("bid") int bid){ return service.getBookById(bid); } }
同樣進行一下測試:
-------------------------------------------------------------------------------------------------------------------------
P5:微服務(wù)項目搭建(三)
前面我們完成了用戶信息查詢和圖書信息查詢,現(xiàn)在我們來接著完成借閱服務(wù)。
借閱服務(wù)是一個關(guān)聯(lián)性比較強的服務(wù),它不僅僅需要查詢借閱信息,同時可能還需要獲取借閱信息下的詳細信息,比如具體那個用戶借閱了哪本書,并且用戶和書籍的詳情也需要同時出現(xiàn),那么這種情況下,我們就需要去訪問除了借閱表以外的用戶表和圖書表。
但是這顯然是違反我們之前所說的單一職責的,相同的業(yè)務(wù)功能不應(yīng)該重復出現(xiàn),但是現(xiàn)在由需要在此服務(wù)中查詢用戶的信息和圖書信息,那怎么辦呢?我們可以讓一個服務(wù)去調(diào)用另一個服務(wù)來獲取信息。
這樣,圖書管理微服務(wù)和用戶管理微服務(wù)相對于借閱記錄,就形成了一個生產(chǎn)者和消費者的關(guān)系,前者是生產(chǎn)者,后者便是消費者。
現(xiàn)在我們先將借閱關(guān)聯(lián)信息查詢完善了:
@Data public class Borrow { int id; int uid; int bid; }
@Mapper public interface BorrowMapper { @Select("select * from DB_BORROW where uid = #{uid}") List<Borrow> getBorrowsByUid(int uid); @Select("select * from DB_BORROW where bid = #{bid}") List<Borrow> getBorrowsByBid(int bid); @Select("select * from DB_BORROW where bid = #{bid} and uid = #{uid}") Borrow getBorrow(int uid, int bid); }
現(xiàn)在有一個需求,需要查詢用戶的借閱詳細信息,也就是說需要查詢某個用戶具體借了那些書,并且需要此用戶的信息和所有已借閱的書籍信息一起返回,那么我們先來設(shè)計一下返回實體:
@Data @AllArgsConstructor public class UserBorrowDetail { User user; List<Book> bookList; }
但是有一個問題,我們發(fā)現(xiàn)User和Book實體實際上是在另外兩個微服務(wù)中定義的,相當于當前項目并沒有定義這些實體類,那么怎么解決呢?
因此,我們可以將所有服務(wù)需要用到的實體類單獨放入另一個一個項目中,然后讓這些項目引用集中存放實體類的那個項目,這樣就可以保證每個微服務(wù)的實體類信息都可以共用了:
然后只需要在對應(yīng)的類中引用此項目作為依賴即可:
<dependency> <groupId>com.example</groupId> <artifactId>commons</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
之后新的公共實體類都可以在
commons
項目中進行定義了,現(xiàn)在我們接著來完成剛剛的需求,先定義接口:public interface BorrowService { UserBorrowDetail getUserBorrowDetailByUid(int uid); }
@Service public class BorrowServiceImpl implements BorrowService{ @Resource BorrowMapper mapper; @Override public UserBorrowDetail getUserBorrowDetailByUid(int uid) { List<Borrow> borrow = mapper.getBorrowsByUid(uid); //那么問題來了,現(xiàn)在拿到借閱關(guān)聯(lián)信息了,怎么調(diào)用其他服務(wù)獲取信息呢? } }
需要進行服務(wù)遠程調(diào)用我們需要用到
RestTemplate
來進行:@Service public class BorrowServiceImpl implements BorrowService{ @Resource BorrowMapper mapper; @Override public UserBorrowDetail getUserBorrowDetailByUid(int uid) { List<Borrow> borrow = mapper.getBorrowsByUid(uid); //RestTemplate支持多種方式的遠程調(diào)用 RestTemplate template = new RestTemplate(); //這里通過調(diào)用getForObject來請求其他服務(wù),并將結(jié)果自動進行封裝 //獲取User信息 User user = template.getForObject("http://localhost:8082/user/"+uid, User.class); //獲取每一本書的詳細信息 List<Book> bookList = borrow .stream() .map(b -> template.getForObject("http://localhost:8080/book/"+b.getBid(), Book.class)) .collect(Collectors.toList()); return new UserBorrowDetail(user, bookList); } }
現(xiàn)在我們再最后完善一下Controller:
@RestController public class BorrowController { @Resource BorrowService service; @RequestMapping("/borrow/{uid}") UserBorrowDetail findUserBorrows(@PathVariable("uid") int uid){ return service.getUserBorrowDetailByUid(uid); } }
在數(shù)據(jù)庫中添加一點借閱信息,測試看看能不能正常獲?。ㄗ⒁庖欢ㄒWC三個服務(wù)都處于開啟狀態(tài),否則遠程調(diào)用會失?。?/p>
可以看到,結(jié)果正常,沒有問題,遠程調(diào)用成功。文章來源:http://www.zghlxwxcb.cn/news/detail-471164.html
這樣,一個簡易的圖書管理系統(tǒng)的分布式項目就搭建完成了,這里記得把整個項目壓縮打包備份一下,下一章學習SpringCloud Alibaba也需要進行配置。文章來源地址http://www.zghlxwxcb.cn/news/detail-471164.html
到了這里,關(guān)于SpringCloud_微服務(wù)基礎(chǔ)day1(走進微服務(wù),認識springcloud,微服務(wù)(圖書管理)項目搭建(一))的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!