放棄 JSP 吧,讓自己的路走的寬一些。。。
前段時(shí)間,我和一位群友因?yàn)橐灰獙W(xué)習(xí) JSP 在群里爭(zhēng)論了一番。他的想法是一定要學(xué),并且還羅列了一個(gè)讓我哭笑不得的理由,那就是“學(xué)習(xí) JSP 可以加深對(duì)Servlet原理的理解!”。當(dāng)時(shí),我整個(gè)人都蒙了,就很氣憤??!這位群友也是工作一年多的人了,不知道為啥會(huì)說(shuō)出這樣的話。
本來(lái)準(zhǔn)備自己寫(xiě)一篇文章來(lái)回懟,后面看了陳龍大佬也寫(xiě)了一篇類(lèi)似的文章,看完之后感覺(jué)非常不錯(cuò)。于是,轉(zhuǎn)載過(guò)來(lái),希望對(duì)大家有幫助。
自從在知乎回答問(wèn)題以來(lái),以及根據(jù)最近幾年給企業(yè)做技術(shù)咨詢的情況,發(fā)現(xiàn) JSP 還是一個(gè)經(jīng)常被提到的問(wèn)題。希望能在這篇文章里把關(guān)于 JSP 的問(wèn)題集中說(shuō)明一下。我的觀點(diǎn)很明確,已經(jīng)寫(xiě)在文章標(biāo)題里了。
確實(shí),很多初學(xué)者,甚至是學(xué)了一兩年的 Java 程序員還在糾結(jié)是否要學(xué) JSP。我認(rèn)為如非工作需要,別學(xué)!
還是老規(guī)矩,有任何疑問(wèn)都可以在評(píng)論區(qū)提出來(lái),有時(shí)間我一定會(huì)解答。我會(huì)把典型問(wèn)題提取到文章正文里,讓更多人看到。有任何錯(cuò)誤,包括錯(cuò)字、語(yǔ)句不通順等問(wèn)題,敬請(qǐng)指正。
我 1998 年開(kāi)始學(xué)習(xí) Java,那時(shí)候?qū)W校里老師可能聽(tīng)說(shuō)過(guò) Java,但是同學(xué)基本上都不知道 Java。校圖書(shū)館進(jìn)第一批 Java 的書(shū),后面的借閱記錄上都是我的名字。當(dāng)時(shí)幾乎所有男同學(xué)都在學(xué) C++、PB、VB、Delphi,女生很多在學(xué) ASP。所以很多同學(xué)問(wèn)我學(xué)的是什么,Java 是干什么的。
大學(xué)畢業(yè)以后,開(kāi)始用 Java 做的第一個(gè)實(shí)際項(xiàng)目是對(duì)日外包,是 2001 年。日方有一套很老的系統(tǒng),想用 Java 重構(gòu)一下,要求用 JSP。我下班就跑去西單圖書(shū)大廈,發(fā)現(xiàn)那里的書(shū)都還是 Servlet 的, 沒(méi)有 JSP 的!
還好,當(dāng)時(shí)的公司同時(shí)進(jìn)行的一項(xiàng)業(yè)務(wù)就是代理 BEA 的 Weblogic(BEA 是三個(gè)從 SUN 出來(lái)的人創(chuàng)建的,后來(lái)被 Oracle 收購(gòu))。Weblogic 的產(chǎn)品文檔里包含非常全面的 JSP 介紹,所以起初對(duì) JSP 的學(xué)習(xí)都是從 Weblogic 開(kāi)始的。
那時(shí)候還沒(méi)聽(tīng)說(shuō)過(guò)什么 Struts。自己在 SUN 的官網(wǎng)發(fā)現(xiàn)了 WAF 的文檔,全稱(chēng)是 Web Application Framework,算是最早 MVC 模式的介紹。這個(gè) WAF 不算是框架,只是介紹了 MVC 模式應(yīng)該是個(gè)什么樣子,如何用 Servlet+JSP 實(shí)現(xiàn) MVC 模式。SUN 的官網(wǎng)提供了少量的樣例代碼,剩下的都是我們根據(jù)文檔自己搭建和實(shí)踐。
在項(xiàng)目的中后期(02 年下半年吧),有一次坐班車(chē),聽(tīng)到后面座位上兩個(gè)人在說(shuō)話。
一個(gè)人問(wèn):你知道 Struts 嗎?另外一個(gè)人說(shuō):不知道。問(wèn)的那個(gè)人說(shuō):就是 S T R U T S 這幾個(gè)字母,開(kāi)發(fā) Java 的。我偷偷記在心里,然后第二天上網(wǎng)查了一下(當(dāng)時(shí)沒(méi)有智能機(jī),家里也沒(méi)有 WIFI),才算開(kāi)啟了 Apache 這扇大門(mén)。后來(lái)在 ASF 上又學(xué)習(xí)了 Cocoon、pluto、turbine 等等很多框架。
大概 02 年底,對(duì)日外包項(xiàng)目順利完成了,我公司開(kāi)始接國(guó)內(nèi)的項(xiàng)目。第一個(gè)國(guó)內(nèi)項(xiàng)目是東北一所大學(xué)的科研經(jīng)費(fèi)審批項(xiàng)目。記得去給人家部署和演示的時(shí)候特別有意思。我們用了半天時(shí)間在服務(wù)器上部署好,然后去給客戶演示。打開(kāi)瀏覽器,輸入 ip+端口,開(kāi)始操作。操作了十幾分鐘,所有的客戶沒(méi)有說(shuō)一個(gè)字。越演示心里越?jīng)]底,不知道客戶啥反應(yīng)。大概又過(guò)了幾分鐘,客戶的主任發(fā)話了:你們的軟件呢?
我們的軟件呢?我給你演示了半天,這不就是我們的軟件嗎?最后才明白,用戶認(rèn)為只有下載一個(gè)類(lèi)似叫 setup.exe 或 install.exe 的程序,雙擊,然后下一步下一步,最后桌面上出現(xiàn)一個(gè)快捷方式,那才算是軟件!在經(jīng)過(guò)片刻的不可思議之后,我認(rèn)為實(shí)際用戶的理念總是落后于研發(fā)人員的理念,這個(gè)我很容易想明白。但后來(lái)發(fā)現(xiàn),我那些學(xué) PB、Delphi 的師兄弟也不是一時(shí)半會(huì)能接受 B/S 結(jié)構(gòu)的應(yīng)用算是軟件的...他們認(rèn)為:你不就是寫(xiě)個(gè)網(wǎng)頁(yè)嗎???
再后來(lái),從 03-08 年,長(zhǎng)期從事企業(yè)應(yīng)用開(kāi)發(fā),主要是基于 Weblogic Platform,包括 Server、Integration、Portal,其中在 Portal 上工作的時(shí)間最多。
其中 04-05 年用 Weblogic Portal 做深圳市最大的電子政務(wù)項(xiàng)目,06-07 年用 Weblogic 平臺(tái)做廣東省電信的 3G 業(yè)務(wù)平臺(tái),08-09 年用 Aqualogic 做南方電網(wǎng)的 SOA。
Weblogic Server 中集成了 Struts,沒(méi)記錯(cuò)的話當(dāng)時(shí)是 1.1 版本。BEA 把 Struts 做了升級(jí)和改造,可以在 Weblogic Workshop 中可視化開(kāi)發(fā),就是下面這樣:
其中圓形代表 Action,有 Begin Action,End Action,還有普通的中間節(jié)點(diǎn) Action。BEA 把 Struts 的這個(gè)升級(jí)稱(chēng)作 Java Page Flow(Java 頁(yè)面流)。一組這樣的圖形當(dāng)中包含的 Action 和 JSP,會(huì)定義在一個(gè)擴(kuò)展名是.jpf 的文件中。
后來(lái),BEA 把 JPF 捐獻(xiàn)給了 Apache,成為 ASF 下的一個(gè)開(kāi)源項(xiàng)目Apache Beehive。
這個(gè)項(xiàng)目現(xiàn)在已經(jīng)停止更新了。
大概從 06 年開(kāi)始,接觸到了 YUI,也就是 Yahoo User Interface,Yahoo 開(kāi)源的一套前端 JS 組件庫(kù)。從此算是開(kāi)啟了我的前端之路。
07-08 年開(kāi)始用 Extjs,作者說(shuō) Ext 就是 Extension(擴(kuò)展)的意思,擴(kuò)展了 YUI,提供了更豐富的適合企業(yè)開(kāi)發(fā)的前端組件。但這時(shí)候,Extjs 還僅僅是豐富的 UI 組件庫(kù),算不上框架。就是在 JSP 生成的 HTML 里面嵌入 Extjs 的組件。
09-11 年用 GWT,就是 Google Web Toolkits。Google 當(dāng)時(shí)的想法很先進(jìn),用 Java 開(kāi)發(fā)前端 UI,最終編譯成 JS。有點(diǎn)類(lèi)似于現(xiàn)在 TS 編譯成 JS 的過(guò)程,就是打算利用上 Java 的強(qiáng)類(lèi)型、面向?qū)ο蟮忍攸c(diǎn)。這時(shí)候就已經(jīng)完全前后端分離了。可以說(shuō)從 08 年之后我就再也沒(méi)寫(xiě)過(guò) JSP,一個(gè)頁(yè)面也沒(méi)寫(xiě)過(guò)。
10 年開(kāi)始用 Bootstrap。這時(shí)候 GWT 的缺點(diǎn)就暴露出來(lái)了,CSS 非常難改。直到 13 年初,開(kāi)始用上了 Angularjs。記得當(dāng)時(shí)在智聯(lián)招聘上發(fā)布職位的時(shí)候搜了一下,北京市只有用友和我們公司招聘 Angularjs 開(kāi)發(fā)。后來(lái)就從 Angularjs 用到 React,又用回 Angular4,一直到現(xiàn)在都以最新版本的 Angular 為主,企業(yè)應(yīng)用和互聯(lián)網(wǎng)應(yīng)用都有開(kāi)發(fā)。移動(dòng)開(kāi)發(fā)主要用 Ionic,React Native 也用過(guò)。
為什么要詳細(xì)介紹我過(guò)去和 JSP 以及前端框架相關(guān)的開(kāi)發(fā)經(jīng)歷呢?是因?yàn)槲蚁氡磉_(dá)一個(gè)觀點(diǎn):如果要客觀公正評(píng)價(jià) JSP 是否還有必要用,特別是還有必要學(xué),需要一個(gè)真正長(zhǎng)期用過(guò) JSP(前后端不分離)開(kāi)發(fā),也真正長(zhǎng)期用前端框架(前后端分離)開(kāi)發(fā)的人才可以。
就像我在有些知乎答案下評(píng)論的那樣:
遇到這種情況,我總想起福特的名言:“如果我當(dāng)年去問(wèn)顧客他們想要什么,他們肯定會(huì)告訴我:‘一匹更快的馬?!?/span>
滿大街跑馬車(chē)的時(shí)代,福特問(wèn)顧客需要什么,顧客就說(shuō)需要一匹更快的馬。他們不知道汽車(chē)時(shí)代會(huì)給生活帶來(lái)怎樣革命性的變化。
在 BP 機(jī)時(shí)代,大家認(rèn)為有人戴 BP 機(jī)已經(jīng)很牛了。滿大街諾基亞摩托羅拉功能機(jī)的時(shí)代,大家也都覺(jué)得夠用了。問(wèn)他們需要什么,他們估計(jì)會(huì)回答:充一次電能不能待機(jī)一個(gè)月?能不能把自己喜歡的 MP3 當(dāng)彩鈴?
我覺(jué)得要對(duì)比評(píng)價(jià)兩代產(chǎn)品,應(yīng)該給兩代產(chǎn)品都熟練體驗(yàn)過(guò)的人去判斷。從功能機(jī)時(shí)代過(guò)來(lái)的人,現(xiàn)在 iphone 都已經(jīng)用到第三部了,你再問(wèn)他功能機(jī)夠不夠用。就拿一個(gè)兩代產(chǎn)品都具有的功能(比如都可以 QQ 聊天)對(duì)比,你愿意回到功能機(jī)時(shí)代還是繼續(xù)用智能機(jī)。
一直抱定 JSP 不撒手,沒(méi)動(dòng)力、沒(méi)能力學(xué)習(xí)前端技術(shù),沒(méi)有真正理解前后端分離開(kāi)發(fā)模式的人,不可能得出公正全面的評(píng)價(jià)。
在校期間或參加培訓(xùn)班就學(xué)習(xí)了前端框架,參加工作后就開(kāi)始前后端分離的人,也無(wú)法理解老人只用 JSP 或用 JSP+JS 前端 UI 組件的開(kāi)發(fā)模式是個(gè)怎么回事。
上面兩種人,據(jù)我實(shí)際接觸中了解,大部分都認(rèn)為自己的開(kāi)發(fā)模式是理所當(dāng)然的。
就像我之前描述自己剛畢業(yè)時(shí)候的經(jīng)歷一樣。大部分客戶和我的一些同學(xué),理所當(dāng)然認(rèn)為雙擊 setup.exe,然后下一步下一步才是軟件。而我理所當(dāng)然認(rèn)為 B/S 架構(gòu)的也是軟件,只是更便于開(kāi)發(fā)和操作。
過(guò)去一年多,陸陸續(xù)續(xù)在知乎上回答了一些關(guān)于 JSP 的問(wèn)題。當(dāng)然,我的回答都是建議淘汰 JSP,新人小白一定不要再學(xué) JSP 了。我現(xiàn)在集中把這些技術(shù)因素歸納一下。
一個(gè)現(xiàn)代主流 Java Web 應(yīng)用,不管前端、后端、還是微服務(wù)架構(gòu),都在淘汰 JSP。
其中,我認(rèn)為 Java 服務(wù)器端主流技術(shù)還是 Spring(Spring Boot + Spring MVC + Spring Cloud)。
下面三點(diǎn),第一點(diǎn)幾乎盡人皆知,第二點(diǎn)有一部分人清楚,第三點(diǎn)卻很少有人意識(shí)到。
1.前端框架已經(jīng)非常成熟和穩(wěn)定,不需要 JSP
前后端分離已經(jīng)不是什么趨勢(shì)了,而是當(dāng)前 B/S 架構(gòu)開(kāi)發(fā)的主流模式。前后端分離之后,前端只負(fù)責(zé)展現(xiàn)和交互,后端負(fù)責(zé)核心業(yè)務(wù)邏輯。前后端通過(guò) API 進(jìn)行交互,并且最好符合 RESTful 風(fēng)格。服務(wù)器端把數(shù)據(jù)返回給前端就不再關(guān)心這些數(shù)據(jù)用在哪里、如何布局、什么樣式。
這個(gè)層面的原因非常容易理解,也是絕大多數(shù)討論 JSP 是否還有必要學(xué)的時(shí)候里都會(huì)提到的。
2.服務(wù)器端的 Spring MVC/WebFlux 和 Spring Boot 已經(jīng)開(kāi)始拋棄 JSP
從 Spring 5 開(kāi)始,在原有的基于 Servlet 技術(shù)的 Spring MVC 之外增加了一個(gè)新的編程模型,就是 Spring WebFlux。
Spring WebFlux 是響應(yīng)式非阻塞的,而且不支持 Servlet API,所以也就不支持 JSP!
上圖左側(cè)是 Spring 5 新引入的 Spring WebFlux,右側(cè)是大家熟悉的 Spring MVC,兩者并列,Spring 同時(shí)支持。
關(guān)于這一點(diǎn),可以看 Stack Overflow 上面來(lái)自 Spring Framework 和 Spring Boot 團(tuán)隊(duì)成員 Brian Clozel 的回答:
https://stackoverflow.com/questions/46970379/spring-webflux-no-jsp-support?rq=1
很多人可能又會(huì)說(shuō)了:新的 Spring WebFlux 不支持 JSP,那咱們不用就好了,至少 Spring MVC 還是支持 JSP 的啊。那我們繼續(xù)看。
如果我們繼續(xù)使用 Spring Boot+Spring MVC 開(kāi)發(fā),那么 Spring Boot 對(duì) JSP 是有限制的,看官方文檔怎么說(shuō)的:
鏈接在這里:https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-template-engines
其中那行備注:
If possible, JSPs should be avoided. There are several known limitations when using them with embedded servlet containers.盡可能避免用 JSP。當(dāng)使用嵌入式 Servlet 容器時(shí),有一些已知的限制。
關(guān)于這些限制和如何繼續(xù)在 Spring Boot 中使用 JSP,可以自己查一下,知乎里就有好多文章。
Spring Boot 對(duì) JSP 有限制,那咱們就湊合用唄,反正我是寫(xiě) Java 的,我的發(fā)展方向是架構(gòu)師,我正打算學(xué)習(xí)微服務(wù),正在看 Spring Cloud。那咱們就繼續(xù)看看 Spring Cloud 吧。
3.微服務(wù)架構(gòu)下更沒(méi)有 JSP 的用武之地
首先要明白 Spring Boot 和 Spring Cloud 的關(guān)系,看這張圖吧:
右側(cè)綠色的部分都是 Spring Cloud 的組成部分,不管是 API Gateway、Config Dashboard,Service Registry,還是多個(gè) MicroServices,他們都是 Spring Boot 應(yīng)用!或者說(shuō) Spring Boot 是整個(gè) Spring Cloud 的基石(其實(shí)也是 Spring Cloud Data Flow 的基石)。
哦,你明白了,因?yàn)橛?Spring Boot 對(duì) JSP 的限制,而 Spring Cloud 的組成部分都是 Spring Boot 應(yīng)用,所以 Spring Cloud 也對(duì) JSP 有限制。其實(shí)不僅僅是表面上這個(gè)原因,咱們繼續(xù)分析。
如果強(qiáng)行繼續(xù)在 Spring Cloud 環(huán)境中繼續(xù)使用 JSP,那么 JSP 放在哪里?有兩種方案。
- API Gateway 和每個(gè) MicroService 里面都有@Controller以及對(duì)應(yīng)的 JSP。那么這種方案下,不同微服務(wù)中的 JSP 如何通信?用戶訪問(wèn)的時(shí)候,同一個(gè)應(yīng)用下的所有 JSP 頁(yè)面會(huì)在不同 IP 和端口下來(lái)回變換。一會(huì)是http://ip0:8081/xxx/xxx.jsp,一會(huì)是http://ip1:8082/xxx/xxx.jsp,點(diǎn)個(gè)連接又跳轉(zhuǎn)到http://ip2:8080/xxx/xxx.jsp....
- 把整個(gè)微服務(wù)應(yīng)用下的所有@Controller和 JSP 都放在 API Gateway 里面,其他 Microservice 中只有提供 REST API 的@Controller和@Service。這種方案并不算理想的微服務(wù)架構(gòu),因?yàn)?Gateway 沒(méi)有解耦,里面的所有@Controller不能拆分部署。這樣就相當(dāng)于在 MicroService 架構(gòu)下有了一個(gè)局部的 Monolithic(單體應(yīng)用)。
那怎么才算是使用 Spring Cloud 的正確姿勢(shì)?還是看上面那幅圖,這次關(guān)注左側(cè)三個(gè)灰色的部分。IoT(物聯(lián)網(wǎng) Internet of Things)、Mobile(移動(dòng)應(yīng)用)、Browser(瀏覽器端),這三個(gè)也是應(yīng)用啊。
我們?cè)倏匆环鶊D:
整個(gè) Spring 體系的圖出來(lái)了。還是看左側(cè),Your App,也就是 IoT(物聯(lián)網(wǎng) Internet of Things)、Mobile(移動(dòng)應(yīng)用)、Browser(瀏覽器端)這三類(lèi)!
Browser 就是前后端分離之后的前端應(yīng)用,獨(dú)立開(kāi)發(fā)、獨(dú)立部署、只和服務(wù)器端有 HTTP RESTful 通信。
我們看看 Spring 官方給出的 Spring Cloud 例子,鏈接在這里:https://spring.io/projects/spring-cloud#samples 。
customers-stores-ui 是前端應(yīng)用,用 Angularjs 實(shí)現(xiàn)的。例子是便于學(xué)習(xí)的,不應(yīng)該引入額外的太多其他技術(shù)!為什么 Spring 官方的例子非要用上前端技術(shù)?不能只用服務(wù)器端開(kāi)發(fā)人員熟悉的模板引擎(包括 JSP)來(lái)演示 Spring Cloud 嗎?
我們?cè)倏戳硗庖粋€(gè)例子,Spring 的 Petclinic 大家都熟悉吧?Spring 官方例子:https://github.com/spring-projects/spring-petclinic 。
官方的是 Monolithic(單體)應(yīng)用,模板用的是 Thymeleaf,自己去看代碼。
用 Spring Cloud 實(shí)現(xiàn)的版本:https://github.com/spring-petclinic 。
前端有 Angular 和 React 兩種實(shí)現(xiàn),服務(wù)器端有 Java 和 Kotlin 兩種實(shí)現(xiàn),都沒(méi)有用服務(wù)器端模板。
同樣的問(wèn)題。為什么演示 Spring Cloud 的開(kāi)發(fā),要引入額外的前端技術(shù)?
答案都是同樣的,Spring Cloud 就必須前后端分離開(kāi)發(fā)!用 JSP 就無(wú)法完美拆分微服務(wù),無(wú)法利用微服務(wù)本應(yīng)帶來(lái)的各種優(yōu)勢(shì)。
總結(jié):
我曾經(jīng)在知乎某一個(gè)問(wèn)題下總結(jié)過(guò):現(xiàn)在 JSP 處于被前后端夾擊的狀態(tài),生存空間越來(lái)越小了。就算你不打算管前端,只想在服務(wù)器端有所建樹(shù)。微服務(wù)的前提也必須前后端分離。
放棄 JSP 吧,讓自己的路走的寬一些。如果死守 JSP 不放,服務(wù)器端只能停留在 SSH/SSM 階段,用 Spring Boot+Spring MVC 已經(jīng)是你的天花板了。
來(lái)源:https://zhuanlan.zhihu.com/p/71937497
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。