摘要:每個(gè)服務(wù)運(yùn)行在其獨(dú)立的進(jìn)程中,服務(wù)與服務(wù)間采用輕量級(jí)的通信機(jī)制互相溝通通常是基于的。在微服務(wù)架構(gòu)下,故障會(huì)被隔離在單個(gè)服務(wù)中。
1. 源碼下載地址
源碼鏈接: https://github.com/samt007/xy...
這是用Spring Cloud微服務(wù)架構(gòu)搭建的一套基于EBS的API服務(wù)系統(tǒng)2. Introduction介紹如對(duì)本文有任何的疑問,請(qǐng)聯(lián)系我:samt007@qq.com
這是一篇傳統(tǒng)ERP系統(tǒng)和基于Java的微服務(wù)架構(gòu)有效結(jié)合的技術(shù)文檔。
傳統(tǒng)ERP關(guān)注的是企業(yè)內(nèi)部的信息化管理。當(dāng)ERP系統(tǒng)能將其服務(wù)發(fā)布出去之后(結(jié)合微服務(wù)架構(gòu)),就可以很好實(shí)現(xiàn)與第三方系統(tǒng)的無縫對(duì)接,同時(shí)也可以實(shí)現(xiàn)擴(kuò)展ERP本身的功能。2.1 它有什么用?
目標(biāo)是:讓ERP的服務(wù)更開放!
簡單來說,就是:
相當(dāng)于做一個(gè)中間服務(wù)平臺(tái),把ERP的功能做成Web Service與其它系統(tǒng)集成。
下面具體說明它的作用。
1. 如果沒有它...如果沒有一個(gè)統(tǒng)一的API對(duì)接平臺(tái),那么ERP和第三方系統(tǒng)做對(duì)接,那會(huì)是下圖所示的結(jié)構(gòu):
從上圖可以看出,各個(gè)第三方系統(tǒng)分別和ERP做對(duì)接,無論是DBLINK還是通過自己的Web Service, 都是雜亂的,沒能統(tǒng)一管理的。簡單來說就是各自為政,為對(duì)接而需要做的事情都是零碎的。
當(dāng)?shù)谌较到y(tǒng)越來越多的時(shí)候,那對(duì)于日常的運(yùn)維將會(huì)是一個(gè)災(zāi)難的問題。舉個(gè)例子,就一個(gè)簡單的運(yùn)維:密碼修改,需要調(diào)整的地方就會(huì)很多,也很容易遺漏。
特別指出的是,接口功能的復(fù)用方面也是個(gè)難題。假設(shè)一個(gè)查詢庫存的接口,CRM系統(tǒng)和在線下單系統(tǒng)都可以用的,需要開發(fā)2次。
2. 自從有了它...有了這套統(tǒng)一的API系統(tǒng)之后,ERP系統(tǒng)和別的系統(tǒng)之間的對(duì)接就變成了這個(gè)結(jié)構(gòu):
所以,有了它,相當(dāng)于ERP的API都可以通過這服務(wù)平臺(tái)給開發(fā)出去,基本上所有的接口可以完成的業(yè)務(wù),都可以通過這套服務(wù)平臺(tái)來完成。
可以實(shí)現(xiàn):
對(duì)外服務(wù)的統(tǒng)一
API服務(wù)之間可以實(shí)現(xiàn)互相調(diào)用,并且實(shí)現(xiàn)服務(wù)取數(shù)和處理的邏輯的統(tǒng)一
代碼的統(tǒng)一,提高開發(fā)效率。特別是comm代碼的部分。
提高與第三方系統(tǒng)對(duì)接的穩(wěn)定性:只需要關(guān)注該微服務(wù)系統(tǒng)的運(yùn)行穩(wěn)定性即可。
3. 有哪些實(shí)例?舉個(gè)例子:
1) 成品進(jìn)出條碼管理系統(tǒng):大概這個(gè)需求:
成品入庫的時(shí)候,直接可以用條碼槍掃條碼或者二維碼就可以入庫;銷售出庫的時(shí)候,也可以通過刷成品的條碼直接進(jìn)行出庫。JIT管理。
通過這個(gè)系統(tǒng)的實(shí)現(xiàn)邏輯是:
通過EBS的用戶名和密碼可以登入條碼槍上的APP系統(tǒng)。然后,刷條碼的時(shí)候,通過該Web Service可以產(chǎn)生對(duì)應(yīng)的事務(wù)處理!例如完工入庫,處理物料搬運(yùn)單等。
下面是該系統(tǒng)的一些截圖
注意:該功能后臺(tái)API由該微服務(wù)提供,前臺(tái)是安卓的APP2) 與各個(gè)第三方系統(tǒng)的集成:
每個(gè)企業(yè)內(nèi)部都有各種第三方系統(tǒng),這些系統(tǒng)或多或少都需要和EBS進(jìn)行集成。傳統(tǒng)的集成方法是通過DBLINK。
但是有這套Web Service系統(tǒng)之后,就可以統(tǒng)一通過該Web Service作為中介,和EBS進(jìn)行數(shù)據(jù)的集成交互!
2.2 什么是微服務(wù)?關(guān)于它的解析,網(wǎng)上資料很多。
這里引用某位大神的總結(jié)(引用:http://blog.51cto.com/ityoukn...),解析得比較到位:
微服務(wù)的概念源于2014年3月Martin Fowler所寫的一篇文章“Microservices”。2.3 ERP API微服務(wù)系統(tǒng)架構(gòu)說明 2.3.1 系統(tǒng)開發(fā)邏輯說明微服務(wù)架構(gòu)是一種架構(gòu)模式,它提倡將單一應(yīng)用程序劃分成一組小的服務(wù),服務(wù)之間互相協(xié)調(diào)、互相配合,為用戶提供最終價(jià)值。每個(gè)服務(wù)運(yùn)行在其獨(dú)立的進(jìn)程中,服務(wù)與服務(wù)間采用輕量級(jí)的通信機(jī)制互相溝通(通常是基于HTTP的RESTful
API)。每個(gè)服務(wù)都圍繞著具體業(yè)務(wù)進(jìn)行構(gòu)建,并且能夠被獨(dú)立地部署到生產(chǎn)環(huán)境、類生產(chǎn)環(huán)境等。另外,應(yīng)盡量避免統(tǒng)一的、集中式的服務(wù)管理機(jī)制,對(duì)具體的一個(gè)服務(wù)而言,應(yīng)根據(jù)業(yè)務(wù)上下文,選擇合適的語言、工具對(duì)其進(jìn)行構(gòu)建。微服務(wù)是一種架構(gòu)風(fēng)格,一個(gè)大型復(fù)雜軟件應(yīng)用由一個(gè)或多個(gè)微服務(wù)組成。系統(tǒng)中的各個(gè)微服務(wù)可被獨(dú)立部署,各個(gè)微服務(wù)之間是松耦合的。每個(gè)微服務(wù)僅關(guān)注于完成一件任務(wù)并很好地完成該任務(wù)。在所有情況下,每個(gè)任務(wù)代表著一個(gè)小的業(yè)務(wù)能力。
微服務(wù)架構(gòu)優(yōu)勢
復(fù)雜度可控:在將應(yīng)用分解的同時(shí),規(guī)避了原本復(fù)雜度無止境的積累。每一個(gè)微服務(wù)專注于單一功能,并通過定義良好的接口清晰表述服務(wù)邊界。由于體積小、復(fù)雜度低,每個(gè)微服務(wù)可由一個(gè)小規(guī)模開發(fā)團(tuán)隊(duì)完全掌控,易于保持高可維護(hù)性和開發(fā)效率。
獨(dú)立部署:由于微服務(wù)具備獨(dú)立的運(yùn)行進(jìn)程,所以每個(gè)微服務(wù)也可以獨(dú)立部署。當(dāng)某個(gè)微服務(wù)發(fā)生變更時(shí)無需編譯、部署整個(gè)應(yīng)用。由微服務(wù)組成的應(yīng)用相當(dāng)于具備一系列可并行的發(fā)布流程,使得發(fā)布更加高效,同時(shí)降低對(duì)生產(chǎn)環(huán)境所造成的風(fēng)險(xiǎn),最終縮短應(yīng)用交付周期。
技術(shù)選型靈活:微服務(wù)架構(gòu)下,技術(shù)選型是去中心化的。每個(gè)團(tuán)隊(duì)可以根據(jù)自身服務(wù)的需求和行業(yè)發(fā)展的現(xiàn)狀,自由選擇最適合的技術(shù)棧。由于每個(gè)微服務(wù)相對(duì)簡單,故需要對(duì)技術(shù)棧進(jìn)行升級(jí)時(shí)所面臨的風(fēng)險(xiǎn)就較低,甚至完全重構(gòu)一個(gè)微服務(wù)也是可行的。
容錯(cuò):當(dāng)某一組建發(fā)生故障時(shí),在單一進(jìn)程的傳統(tǒng)架構(gòu)下,故障很有可能在進(jìn)程內(nèi)擴(kuò)散,形成應(yīng)用全局性的不可用。在微服務(wù)架構(gòu)下,故障會(huì)被隔離在單個(gè)服務(wù)中。若設(shè)計(jì)良好,其他服務(wù)可通過重試、平穩(wěn)退化等機(jī)制實(shí)現(xiàn)應(yīng)用層面的容錯(cuò)。
擴(kuò)展:單塊架構(gòu)應(yīng)用也可以實(shí)現(xiàn)橫向擴(kuò)展,就是將整個(gè)應(yīng)用完整的復(fù)制到不同的節(jié)點(diǎn)。當(dāng)應(yīng)用的不同組件在擴(kuò)展需求上存在差異時(shí),微服務(wù)架構(gòu)便體現(xiàn)出其靈活性,因?yàn)槊總€(gè)服務(wù)可以根據(jù)實(shí)際需求獨(dú)立進(jìn)行擴(kuò)展。
從上面的解析得知:微服務(wù)是一種技術(shù)架構(gòu),將一個(gè)龐大的服務(wù)體系拆分為若干個(gè)子服務(wù)執(zhí)行。
問題來了,應(yīng)該如何拆分呢?就是服務(wù)的拆分原則是什么。
這個(gè)問題就像是一個(gè)大表如何進(jìn)行分區(qū)一樣,其實(shí)我覺得是具體問題具體分析。
由于我開發(fā)的是基于EBS的微服務(wù)系統(tǒng),正常來說,比較合理的劃分規(guī)則應(yīng)該是以EBS的模塊來分。
相當(dāng)于每個(gè)模塊都劃分為一個(gè)多帶帶的微服務(wù)。例如FND模塊,INV模塊,WIP模塊等等。
有時(shí)候,為了某個(gè)目的,可能有些功能是定制的,需要提取幾個(gè)模塊的數(shù)據(jù)來用,而且被別的模塊重用的概率很低。所以,實(shí)際上也可以以定制的功能來劃分微服務(wù)。
目前來說,該系統(tǒng)包括2個(gè)子服務(wù):
xygerp-ald服務(wù):ald模塊
這個(gè)是整個(gè)微服務(wù)API的核心ald模塊。這個(gè)模塊的主要功能是驗(yàn)證用戶的登錄,為所有的api模塊提供統(tǒng)一的token認(rèn)證。相當(dāng)于ebs的FND模塊。
xygerp-albc服務(wù):albc子模塊
這個(gè)項(xiàng)目是屬于微服務(wù)的API模塊之一:條碼管理系統(tǒng)提供數(shù)據(jù)以及數(shù)據(jù)處理的API。2.3.2 微服務(wù)系統(tǒng)架構(gòu)圖
主要是為條形碼傳輸系統(tǒng)用。當(dāng)然,未來可以添加若干個(gè)服務(wù)。微服務(wù)架構(gòu)的優(yōu)勢是有很好的橫向擴(kuò)展能力!
該系統(tǒng)的架構(gòu)圖如下所示。
注意:
1.Spring Cloud模塊中,實(shí)際上Spring Security并不是多帶帶的一個(gè)模塊,而是融入到每一個(gè)業(yè)務(wù)微服務(wù)模塊中! 每個(gè)微服務(wù)都必須要有token認(rèn)證才允許訪問API,它非常重要! 所以我將它給列到Spring Cloud模塊中。
2.圖中有些模塊目前還沒有實(shí)現(xiàn)。
目前實(shí)現(xiàn)了架構(gòu)整體,包括以下的服務(wù)(下一個(gè)章節(jié)會(huì)具體說明每個(gè)模塊的用途):
xygerp-ald
xygerp-albc
xygerp-server-eureka
xygerp-server-zuul
注意: 以后會(huì)按需添加別的模塊。3 系統(tǒng)開發(fā)流程
接下來是一步一步來開發(fā)一套這個(gè)基于Spring Cloud的微服務(wù)系統(tǒng)。
3.1 必須掌握的基礎(chǔ)開發(fā)技術(shù)知識(shí)點(diǎn)開發(fā)系統(tǒng)都必須要打好基礎(chǔ)。所以,這里列出了開發(fā)基于Spring Cloud的微服務(wù)系統(tǒng)需要掌握的開發(fā)技術(shù)。
下面我不會(huì)具體解說每一個(gè)開發(fā)技術(shù)如何學(xué)習(xí),因?yàn)檫@并不是本文的重點(diǎn)。工欲善其事必先利其器,基礎(chǔ)還是必須要打好。1)Java語言
必須要熟悉java,否則基本不用看文檔了。先打好基礎(chǔ)吧!
2)Maven項(xiàng)目管理工具系統(tǒng)開發(fā)的項(xiàng)目都是以maven做項(xiàng)目管理的,所以必須要先安裝并掌握maven工具。
3)Oracle數(shù)據(jù)庫+PLSQL+SQL語言數(shù)據(jù)庫端的開發(fā)技術(shù)。這里選用Oracle數(shù)據(jù)庫,因?yàn)镋BS就是基于Oracle數(shù)據(jù)庫的ERP系統(tǒng)。
3.2 需要熟悉的java框架Java技術(shù)發(fā)展到現(xiàn)在,已經(jīng)出現(xiàn)了許多非常優(yōu)秀的開源框架,我們可以借助這些框架來快速開發(fā)系統(tǒng)。
3.2.1 Spring框架技術(shù)棧(全家桶)Spring是目前開源的主流的技術(shù)包。
該系統(tǒng)主要用到的技術(shù)棧是:Spring boot,Spring Security以及Spring Cloud。
系統(tǒng)基于SpringBoot快速開發(fā)。選擇目前熱度很高的SpringBoot,最大限度地降低配置復(fù)雜度,把大量的精力投入到業(yè)務(wù)開發(fā)中來。
2.Spring MVC利用Spring MVC框架處理所有的url請(qǐng)求,簡單易用。
3.Spring SecuritySpring security是一個(gè)強(qiáng)大的和高度可定制的身份驗(yàn)證和訪問控制框架。它是確保基于Spring的應(yīng)用程序的標(biāo)準(zhǔn)。
這里主要是用Spring Security框架處理Token機(jī)制。
Spring Cloud是一系列框架的有序集合。
它利用Spring Boot的開發(fā)便利性巧妙地簡化了分布式系統(tǒng)基礎(chǔ)設(shè)施的開發(fā),如服務(wù)發(fā)現(xiàn)注冊(cè)、配置中心、消息總線、負(fù)載均衡、斷路器、數(shù)據(jù)監(jiān)控等,都可以用Spring Boot的開發(fā)風(fēng)格做到一鍵啟動(dòng)和部署。
注意:本系統(tǒng)目前使用Spring Cloud的2個(gè)模塊
請(qǐng)求統(tǒng)一通過API網(wǎng)關(guān)(Zuul)來訪問內(nèi)部服務(wù).
網(wǎng)關(guān)接收到請(qǐng)求后,從注冊(cè)中心(Eureka)獲取可用服務(wù)
3.2.2 MyBatisORM框架選用MyBatis。
主要是考慮到它能夠很好支持SQL語句:MyBatis是支持普通SQL查詢,存儲(chǔ)過程和高級(jí)映射的優(yōu)秀持久層框架。
另外,還用到了MyBatis的一些提高開發(fā)效率的插件,特別是通用Mapper和PageHelper分頁插件!
DRUID是阿里巴巴開源平臺(tái)上一個(gè)數(shù)據(jù)庫連接池實(shí)現(xiàn)。它結(jié)合了C3P0、DBCP、PROXOOL等DB池的優(yōu)點(diǎn),同時(shí)加入了日志監(jiān)控,可以很好的監(jiān)控DB池連接和SQL的執(zhí)行情況。
3.2.4 Swagger前端和后端的唯一聯(lián)系,變成了API接口。
API文檔變成了前后端開發(fā)人員聯(lián)系的紐帶,變得越來越重要,swagger就是一款讓你更好的書寫API文檔的框架。
3.3 需要準(zhǔn)備的軟件工具 3.3.1Redis目前用Redis的主要作用是存取token,以配合實(shí)現(xiàn)Spring Security完成api訪問的安全機(jī)制。
以后可以考慮做緩存或者消息隊(duì)列等高級(jí)功能。3.3.2Docker
基于Docker的容器化部署。
由于使用了微服務(wù)架構(gòu)后,我們的系統(tǒng)將會(huì)由很多子系統(tǒng)構(gòu)成。
為了達(dá)到多個(gè)系統(tǒng)之間環(huán)境隔離的目的,我們可以將它們部署在多臺(tái)服務(wù)器上,可這樣的成本會(huì)比較高,而且每臺(tái)服務(wù)器的性能可能都沒有充分利用起來。
所以我們很自然地想到了虛擬機(jī),在同一臺(tái)服務(wù)器上運(yùn)行多個(gè)虛擬機(jī),從而實(shí)現(xiàn)環(huán)境的隔離,每個(gè)虛擬機(jī)上運(yùn)行獨(dú)立的服務(wù)。
然而虛擬機(jī)的隔離成本依舊很高,因?yàn)樗枰加梅?wù)器較多的硬件資源和軟件資源。
所以,在微服務(wù)結(jié)構(gòu)下,要實(shí)現(xiàn)服務(wù)環(huán)境的隔離,Docker是最佳選擇。它比虛擬機(jī)更加輕量級(jí),占用資源較少,而且能夠?qū)崿F(xiàn)快速部署。
備注:后面有專題說明這個(gè)工具如何安裝使用。由于篇幅原因,本文檔暫時(shí)不講解容器化部署。3.3.3 Jenkins
Jenkins自動(dòng)化構(gòu)建工具。
當(dāng)我們采用了微服務(wù)架構(gòu)后,我們會(huì)發(fā)現(xiàn)這樣一個(gè)問題。整個(gè)系統(tǒng)由許許多多的服務(wù)構(gòu)成,這些服務(wù)都需要運(yùn)行在多帶帶的容器中,那么每次發(fā)布的復(fù)雜度將非常高。
首先你要搞清楚這些服務(wù)之間的依賴關(guān)系、啟動(dòng)的先后順序,然后再將多個(gè)子系統(tǒng)挨個(gè)編譯、打包、發(fā)布。這些操作技術(shù)難度低,卻又容易出錯(cuò)。
那么有什么工具能夠幫助我們解決這些問題呢?答案就是——Jenkins。
它是一款自動(dòng)化構(gòu)建的工具,簡單的來說,就是我們只需要在它的界面上按一個(gè)按鈕,就可以實(shí)現(xiàn)上述一系列復(fù)雜的過程。
備注:后面有專題說明這個(gè)工具如何安裝使用。由于篇幅原因,本文檔暫時(shí)不講解自動(dòng)化構(gòu)建。3.4 具體開發(fā)流程
現(xiàn)在開始手把手來搭建一套這樣子的系統(tǒng)。
3.4.1 創(chuàng)建Maven項(xiàng)目的組織結(jié)構(gòu)先創(chuàng)建一個(gè)微服務(wù)系統(tǒng)的父級(jí)項(xiàng)目:xygerp-api
再在這個(gè)項(xiàng)目下面分別創(chuàng)建下面幾個(gè)子項(xiàng)目:
項(xiàng)目名稱 | 說明 |
---|---|
xygerp-ald | ald模塊,端口:8180。這個(gè)是整個(gè)微服務(wù)API的核心ald模塊。這個(gè)模塊的主要功能是驗(yàn)證用戶的登錄,為所有的api模塊提供統(tǒng)一的token認(rèn)證。相當(dāng)于ebs的FND模塊。 |
xygerp-albc | albc子模塊,端口:8181。這個(gè)項(xiàng)目是屬于微服務(wù)的API模塊之一:條碼管理系統(tǒng)提供數(shù)據(jù)以及數(shù)據(jù)處理的API。主要是為條形碼傳輸系統(tǒng)用。 |
xygerp-comm | comm模塊這個(gè)項(xiàng)目是所有API項(xiàng)目的核心依賴項(xiàng)目。說白了就是將API微服務(wù)架構(gòu)的所有項(xiàng)目的公用代碼可以抽取在這里。 |
xygerp-basic-support | 核心基礎(chǔ)支撐模塊這個(gè)項(xiàng)目是所有API項(xiàng)目的基礎(chǔ)數(shù)據(jù)支撐項(xiàng)目。這里統(tǒng)一歸集了所有的Entity!因?yàn)閷?duì)于Entity來說,應(yīng)該是整個(gè)微服務(wù)都公用的。 |
xygerp-server-eureka | Spring Cloud的服務(wù)與發(fā)現(xiàn)的服務(wù)中心。端口:8101。這個(gè)模塊是Spring cloud的最核心的模塊了,用來處理各個(gè)微服務(wù)之間的服務(wù)調(diào)用的。 |
xygerp-server-zuul | Spring Cloud服務(wù)網(wǎng)關(guān)。端口:8102。在Spring Cloud架構(gòu)體系內(nèi)的所有微服務(wù)都通過Zuul來對(duì)外提供統(tǒng)一的訪問入口,所有需要和微服務(wù)架構(gòu)內(nèi)部服務(wù)進(jìn)行通訊的請(qǐng)求都走統(tǒng)一網(wǎng)關(guān)。 |
注意:3.4.2 構(gòu)建模塊的依賴關(guān)系
關(guān)于xygerp-basic-support:核心基礎(chǔ)支撐模塊可能您會(huì)有疑問:為什么不將entity歸并在它所屬的模塊?其實(shí)是這樣的,我主要是考慮到服務(wù)之間的互相調(diào)用的問題。
微服務(wù)雖然客觀上是一個(gè)多帶帶的服務(wù),但是,實(shí)際上大部分的功能肯定是互相調(diào)用的。舉個(gè)例子,銷售訂單模塊調(diào)用庫存模塊的功能查詢個(gè)庫存是很正常的業(yè)務(wù)吧?
如果entity不共用的話,相當(dāng)于銷售模塊得到的庫存模塊的結(jié)果無法歸集為bean來處理,這樣子對(duì)于后臺(tái)的處理會(huì)帶來極大的不便!
接著需要通過pom文件來指定它們之間的依賴關(guān)系,依賴關(guān)系如下圖所示。
1. 業(yè)務(wù)服務(wù)部分:
注意,上面的4個(gè)項(xiàng)目是有依賴關(guān)系的。
所以,xygerp-ald和xygerp-albc部署方式 改為war部署 (主要是為了利用jenkins進(jìn)行自動(dòng)化部署)。
而xygerp-comm和xygerp-basic-support只是為各個(gè)微服務(wù)提供基礎(chǔ)代碼支撐,所以是jar部署即可。
此外,為了簡化各個(gè)模塊的配置,我們將所有模塊的通用依賴放在Project的pom文件中,然后讓所有模塊作為Project的子模塊。
這樣子模塊就可以從父模塊中繼承所有的依賴,而不需要自己再配置了。
在父pom中指定子模塊
modules標(biāo)簽指定了當(dāng)前模塊的子模塊是誰,但是僅在父模塊的pom文件中指定子模塊還不夠,還需要在子模塊的pom文件中指定父模塊是誰。
xygerp-comm xygerp-basic-support xygerp-server-eureka xygerp-server-zuul xygerp-ald xygerp-albc
需要在子模塊中指定父模塊
xygerp com.xygerp 1.0-SNAPSHOT ../pom.xml
備注:具體代碼直接看源碼吧。這里只是提及了一些重點(diǎn)設(shè)置而已。
所以,到此為止,模塊的依賴關(guān)系配置完畢!但要注意模塊打包的順序。
由于所有模塊都依賴于xygerp-comm模塊和xygerp-basic-support模塊,因此在構(gòu)建模塊時(shí),首先需要編譯、打包、安裝xygerp-comm模塊和xygerp-basic-support模塊,將它打包進(jìn)本地倉庫中,這樣上層模塊才能引用到。當(dāng)該模塊安裝完畢后,再構(gòu)建上層模塊。
否則在構(gòu)建上層模塊的時(shí)候會(huì)出現(xiàn)找不到xygerp-comm模塊中類庫的問題。
Tips: 其實(shí),如果是在父級(jí)目錄直接用mvn package整體打包的話,那打包構(gòu)建的順序在父pom中是直接指定了!2. 微服務(wù)架構(gòu)服務(wù)治理部分
xygerp-server-eureka:Spring Cloud服務(wù)注冊(cè)和發(fā)現(xiàn)。就是處理服務(wù)之間的治理。
xygerp-server-zuul:Spring Cloud的統(tǒng)一API網(wǎng)關(guān)服務(wù)。
Tips: 這2個(gè)項(xiàng)目是為了實(shí)現(xiàn)微服務(wù)架構(gòu)而用到的核心服務(wù)。所以,它們是相對(duì)獨(dú)立的。不需要依賴父pom。3.4.3用mvn編譯命令打包代碼
上面的項(xiàng)目都建立好之后,再添加所有項(xiàng)目都需要用到的依賴(具體代碼可以參考我的源碼)。
都沒問題的話,就可以用mvn命令進(jìn)行打包項(xiàng)目了:
mvn clean install -Dmaven.test.skip=true -P dev
這里簡單解析一下指令:mvn:Maven的統(tǒng)一指令。
clean install:表示要構(gòu)建該項(xiàng)目。
-Dmaven.test.skip=true:表示構(gòu)建的時(shí)候要跳過測試模塊。
-P dev:表示構(gòu)建的時(shí)候,啟用 dev 的Spring boot參數(shù)運(yùn)行系統(tǒng)。
如果一切都OK,那正常的結(jié)果如下:
3.5 本地電腦測試系統(tǒng)代碼搞定了,接下來需要考慮的事情應(yīng)該是如何測試。
畢竟所有的系統(tǒng)都必須要經(jīng)過測試,特別是這種配置多,涉及范圍廣的系統(tǒng)。
這個(gè)就不得不說一下Spring boot的優(yōu)勢了。Spring boot的打包應(yīng)用默認(rèn)內(nèi)置了tomcat服務(wù)。3.5.1 啟動(dòng)本地系統(tǒng)的服務(wù)
換句話說,只需要java命令執(zhí)行一下Spring boot打包的target結(jié)果,就可以啟動(dòng)一個(gè)tomcat服務(wù)啦!真挺方便測試的!
假設(shè)我的xygerp-api項(xiàng)目在這里:D:JSP_MyEclipsexygerp-api
然后分別打開4個(gè)cmd命令窗口,執(zhí)行:
D:JSP_MyEclipsexygerp-apixygerp-server-eureka arget>java -jar xygerp-server-eureka-1.0-SNAPSHOT.war D:JSP_MyEclipsexygerp-apixygerp-server-zuul arget>java -jar xygerp-server-zuul-1.0-SNAPSHOT.war D:JSP_MyEclipsexygerp-apixygerp-ald arget>java -jar xygerp-ald-1.0-SNAPSHOT.war D:JSP_MyEclipsexygerp-apixygerp-albc arget>java -jar xygerp-albc-1.0-SNAPSHOT.war
如下圖:
本地測試環(huán)境的服務(wù)啟動(dòng)起來了,接著就是進(jìn)行具體的數(shù)據(jù)測試。
首先測試Eureka的服務(wù)注冊(cè)以及發(fā)現(xiàn),確認(rèn)服務(wù)是否都已經(jīng)注冊(cè)到系統(tǒng)中:
然后,用swagger測試用戶登錄的功能:
http://127.0.0.1:8102/xygerp/ald/swagger-ui.html
目前是測試是否可以正常產(chǎn)生token。
說明已經(jīng)登錄成功,并且產(chǎn)生了本次訪問的token!
將token記錄下來,接著測試。
繼續(xù)測試一個(gè)查詢的功能:
http://127.0.0.1:8102/xygerp/albc/swagger-ui.html
注意,這里用了Spring Security框架,所以的API請(qǐng)求頭都必須攜帶token信息。否則請(qǐng)求會(huì)返回401。
如果測試OK,那說明基本上系統(tǒng)已經(jīng)成功搭建好了。
下一步就是如何在測試環(huán)境或者正式環(huán)境部署它,以及如何一鍵構(gòu)建項(xiàng)目的問題了。
簡單來說,系統(tǒng)的部署是用 docker工具 ,一鍵部署項(xiàng)目用的是 Jenkins工具。后面將會(huì)用專題來說明這2個(gè)工具的使用。3.6 該API微服務(wù)系統(tǒng)實(shí)現(xiàn)的功能難點(diǎn) 3.6.1 解決數(shù)據(jù)庫Session的環(huán)境變量問題,特別是語言環(huán)境和用戶環(huán)境。
關(guān)于這個(gè)問題,目前我用的辦法可能不一定是最優(yōu)的,如果有別的兄臺(tái)有更好的解決辦法,請(qǐng)留言給我,十分感謝!
問題來源:
熟悉EBS開發(fā)的兄臺(tái)都應(yīng)該知道,登錄ERP之后,我們每次打開Form,系統(tǒng)就會(huì)申請(qǐng)一個(gè)新的數(shù)據(jù)庫Session,這時(shí)候,EBS系統(tǒng)會(huì) 自動(dòng)幫我們初始化該Session的環(huán)境變量 :例如基本的語言環(huán)境,用戶環(huán)境,業(yè)務(wù)實(shí)體等等。
這時(shí)候,我們?cè)诎锩婵梢灾苯佑肍ND_GLOBAL.USER_ID之類的函數(shù)就可以非常方便獲取環(huán)境變量的信息。
但是,在Java Web開發(fā)里面就不一樣了!
在Java訪問數(shù)據(jù)庫的理念中,Session的申請(qǐng)是一個(gè)極耗資源的動(dòng)作!所以,大部分連接數(shù)據(jù)庫的Java軟件都提出了一個(gè) 數(shù)據(jù)庫連接池 的概念(例如DRUID數(shù)據(jù)庫連接池)。簡單來說就是session共用!
Session公用就會(huì)帶來一個(gè)并發(fā)問題:A用戶使用系統(tǒng),并初始化了該Session的環(huán)境變量為A用戶;當(dāng)A用戶不用系統(tǒng)的時(shí)候,Session會(huì)閑置并放回連接池里面等待別的用戶使用。
這時(shí)候如果B的用戶很可能會(huì)使用該Session,如果不重新初始化環(huán)境變量的話,那B用戶使用系統(tǒng)的Session的環(huán)境變量還是A用戶,就會(huì)導(dǎo)致數(shù)據(jù)的bug!
如何處理該問題是開發(fā)該系統(tǒng)碰到的一個(gè)難題。
問題解決:
我目前的處理辦法是:在Service層,用AOP統(tǒng)一自動(dòng)監(jiān)控Service層的這個(gè)參數(shù)AuthUser user
只要在Service層將參數(shù)AuthUser user放在最后,AOP會(huì)自動(dòng)初始化Session的環(huán)境變量。(需要注意的是,我這個(gè)系統(tǒng)的數(shù)據(jù)庫Transaction在Service層啟用!)
另外,語言環(huán)境變量,登錄ID環(huán)境變量等,會(huì)一并自動(dòng)初始化。因?yàn)锳uthUser會(huì)攜帶該定義!
核心處理代碼如下:
private static final String SQL_GLOBAL_INIT = " DECLARE " + " L_session_id NUMBER;L_user_id NUMBER;L_login_id NUMBER;L_LANG VARCHAR2(10); " + " BEGIN " + " L_user_id:=:P_USER_ID; L_login_id:=:P_LOGIN_ID; L_LANG:=:P_LANG;" + " APPS.fnd_global.INITIALIZE(" + " session_id=>L_session_id, user_id =>L_user_id, resp_id =>NULL, " + " resp_appl_id=>NULL, security_group_id=>NULL, site_id=>NULL, login_id =>L_login_id, " + " conc_login_id=>NULL, prog_appl_id=>NULL, conc_program_id=>NULL, conc_request_id=>NULL, " + " conc_priority_request=>NULL" + " ); " + " IF NVL(L_LANG,"US") <> USERENV("LANG") THEN " + " IF L_LANG="ZHS" THEN " + " APPS.fnd_global.set_nls_context(p_nls_language => "SIMPLIFIED CHINESE"); " + " ELSE " + " APPS.fnd_global.set_nls_context(p_nls_language => "AMERICAN"); " + " END IF;" + " END IF;" + " END; "; /*** * service層調(diào)用之前先自動(dòng)初始化環(huán)境變量 * 需要注意的是,用戶變量必須的參數(shù)放在最后! * 只要在Service層將參數(shù)AuthUser user放在最后,AOP會(huì)自動(dòng)初始化Session的環(huán)境變量。 * @throws Exception */ @SuppressWarnings("static-access") @Before("execution(* com.jebms.*.service..*.*(..)) && args(..,user)") public void oracleDBInit(JoinPoint joinPoint,AuthUser user) throws Exception{ Long dbLoginId=devDao.getJdbcTemplate().queryForObject("SELECT FND_GLOBAL.LOGIN_ID FROM DUAL", Long.class); if(user.getLoginId()!=null&&user.getLoginId()>0&&!user.getLoginId().equals(dbLoginId)){ MapinParamMap=new HashMap (); inParamMap.put("P_USER_ID", user.getUserId()); inParamMap.put("P_LOGIN_ID", user.getLoginId()); inParamMap.put("P_LANG", user.getLanguage()); devDao.getDevJdbcTemplate().execute(this.SQL_GLOBAL_INIT, inParamMap); } }
源代碼在:com.jebms.comm.utils. AopUtil3.6.2 解決EBS的用戶的登錄問題:統(tǒng)一用EBS系統(tǒng)的帳號(hào)密碼登錄API系統(tǒng)。
問題描述:
由于我這個(gè)是第三方的API系統(tǒng),所以,用戶名和密碼信息實(shí)際上并不是該API系統(tǒng)需要管理的事情。
相當(dāng)于說,API系統(tǒng)無法按照正常的流程來驗(yàn)證用戶名和密碼:輸入用戶名和密碼,系統(tǒng)驗(yàn)證后臺(tái)數(shù)據(jù)庫的用戶名和密碼,再返回驗(yàn)證結(jié)果。
而是:輸入用戶名和密碼,系統(tǒng) 調(diào)用ERP的用戶名密碼驗(yàn)證包 進(jìn)行驗(yàn)證,再返回結(jié)果。
簡單來說:需要添加自定義驗(yàn)證的邏輯。
還好Spring Security框架支持靈活的驗(yàn)證邏輯。
添加步驟:
首先,寫一個(gè)自定義驗(yàn)證的類:MyAuthenticationProvider接著,在Spring Security框架的定義中,添加這個(gè)自定義的驗(yàn)證。
AbstractWebSecurityConfig
private MyAuthenticationProvider provider;//自定義驗(yàn)證
auth.authenticationProvider(provider);
即可以完美實(shí)現(xiàn)這個(gè)效果
核心代碼:
/** * 自定義驗(yàn)證方式 */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = (String) authentication.getCredentials(); AuthUser user = (AuthUser) userService.loadUserByUsername(username); System.out.println("username:"+username+",password:"+password); if(user == null){ throw new BadCredentialsException("Username not found."); } //加密過程在這里體現(xiàn) if (!sysService.xygErpValidateLogin(username, password)) { throw new BadCredentialsException("Wrong password."); } user.setPassword(passwordEncoder.encode(password)); Collection extends GrantedAuthority> authorities = user.getAuthorities(); return new UsernamePasswordAuthenticationToken(user, password, authorities); }3.6.3 統(tǒng)一的開發(fā)風(fēng)格。
1.Entity基類封裝。
封裝了5who欄位,以及類似Form的FND_SET_WHO的方法,可以很方便進(jìn)行開發(fā)。
另外,為了防止丟失更新,這邊每次更新前實(shí)際上會(huì)先檢測數(shù)據(jù)的一致性,對(duì)應(yīng)的動(dòng)作也有做了封裝。
2.查詢邏輯的封裝。
查詢功能相對(duì)來說還是會(huì)很多,對(duì)于復(fù)雜的查詢條件如何傳值是一個(gè)難題。
這里封裝了一個(gè)SearchInfo積累,可以統(tǒng)一將所有的查詢條件都放在這個(gè)類,然后在java的Controller層定義好查詢條件對(duì)應(yīng)匹配欄位,系統(tǒng)就可以自動(dòng)產(chǎn)生對(duì)應(yīng)的and條件。
例如:
@GetMapping(value = "/getPageLocator") @ApiOperation(value = "貨位分頁列表接口") public ResultEntity> getPageLocator( @ApiParam(value = "庫存組織ID",required = true) @RequestParam(required = true) int organizationId, @ApiParam(value = "庫別代碼",required = true) @RequestParam(required = true) String subinventoryCode, @ApiParam(value = "貨位代碼",required = false) @RequestParam(required = false) String locatorCode, SearchInfo searchInfo) throws Exception { searchInfo.getConditionMap().put("organizationId", organizationId); searchInfo.getConditionMap().put("subinventoryCode", subinventoryCode); searchInfo.getConditionMap().put("locatorCode", locatorCode); searchInfo.setAuthUser(this.authUser); searchInfo.initSqlCondition(); searchInfo.andSqlCondition("MIL.ORGANIZATION_ID","organizationId"); searchInfo.andSqlCondition("MIL.SUBINVENTORY_CODE","subinventoryCode"); searchInfo.andSqlCondition("MIL.SEGMENT1","locatorCode"); return eslipService.selectForPageLocator(searchInfo); }
3.統(tǒng)一的處理結(jié)果的封裝。
基本上任何一個(gè)處理,要不成功,要不失敗(警告其實(shí)也算失敗)。
這里封裝了一個(gè)返回結(jié)果的基類ResultEntity
@ApiModelProperty(value = "狀態(tài)碼,0表示成功 其他表示失敗", example = "0",position = 1) private String code;
特別需要指出的是,前端獲取或者處理數(shù)據(jù),也是統(tǒng)一要用這個(gè)處理結(jié)果基類的返回。
簡單來說,就是數(shù)據(jù)處理成功/失敗,會(huì)有一個(gè)統(tǒng)一的返回結(jié)果標(biāo)識(shí)。注意,這個(gè)標(biāo)識(shí)和請(qǐng)求的響應(yīng)結(jié)果標(biāo)識(shí)(200)是有所不同的!
請(qǐng)求響應(yīng)標(biāo)識(shí)只是說明web服務(wù)器的響應(yīng)是正常,但,具體的處理結(jié)果可能是處理失敗。
下面是一個(gè)具體的例子(到時(shí)候?qū)嶋H開發(fā)處理的接口處理結(jié)果也是這樣子):
{ "code": "0", "message": "", "description": "", "obj": [{ "createdBy": -1, "creationDate": "2017-10-10 09:37:03", "lastUpdatedBy": 10, "lastUpdateDate": "2017-11-16 14:47:48", "lastUpdateLogin": 96, "valueUUID": null, "id": 2, "applId": 1, "respCode": "BASIC_SET", "menuId": 2, "startDate": "2017-10-10 09:37:03", "endDate": null, "respName": "系統(tǒng)設(shè)置職責(zé)", "description": "系統(tǒng)設(shè)置職責(zé)", "menuCode": "SYSTEM_SET", "menuName": "系統(tǒng)設(shè)置菜單", "enabled": true }], "param1": null, "param2": null, "param3": null, "param4": null, "param5": null, "ok": true }
文檔參考鏈接:
https://juejin.im/entry/5a781...
http://blog.51cto.com/ityoukn...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/69133.html
摘要:微服務(wù)集成服務(wù)間通信微服務(wù)架構(gòu)下,應(yīng)用的服務(wù)直接相互獨(dú)立。微服務(wù)架構(gòu)傾向于降低中心消息總線類似于的依賴,將業(yè)務(wù)邏輯分布在每個(gè)具體的服務(wù)終端。 引言:微服務(wù)是當(dāng)前軟件架構(gòu)領(lǐng)域非常熱門的詞匯,能找到很多關(guān)于微服務(wù)的定義、準(zhǔn)則,以及如何從微服務(wù)中獲益的文章,在企業(yè)的實(shí)踐中去應(yīng)用微服務(wù)的資源卻很少。本篇文章中,會(huì)介紹微服務(wù)架構(gòu)(Microservices Architecture)的基礎(chǔ)概念,...
摘要:微服務(wù)集成服務(wù)間通信微服務(wù)架構(gòu)下,應(yīng)用的服務(wù)直接相互獨(dú)立。微服務(wù)架構(gòu)傾向于降低中心消息總線類似于的依賴,將業(yè)務(wù)邏輯分布在每個(gè)具體的服務(wù)終端。 引言:微服務(wù)是當(dāng)前軟件架構(gòu)領(lǐng)域非常熱門的詞匯,能找到很多關(guān)于微服務(wù)的定義、準(zhǔn)則,以及如何從微服務(wù)中獲益的文章,在企業(yè)的實(shí)踐中去應(yīng)用微服務(wù)的資源卻很少。本篇文章中,會(huì)介紹微服務(wù)架構(gòu)(Microservices Architecture)的基礎(chǔ)概念,...
閱讀 1377·2021-10-08 10:04
閱讀 2681·2021-09-22 15:23
閱讀 2724·2021-09-04 16:40
閱讀 1172·2019-08-29 17:29
閱讀 1492·2019-08-29 17:28
閱讀 2988·2019-08-29 14:02
閱讀 2220·2019-08-29 13:18
閱讀 838·2019-08-23 18:35