本文是在學習軟體工程與J2EE課程時的學習筆記,旨在從大體的概念上瞭解Java EE的一些主要組件在Web應用中的作用。 上圖精煉的描述了MVC模型以及Java EE的部分組件如何分佈在一個Web應用上,下文所提到的圖示均指該圖。 Web應用 在開始一切之前要瞭解什麼是Web應用,對於圖中最左側的用 ...
本文是在學習軟體工程與J2EE課程時的學習筆記,旨在從大體的概念上瞭解Java EE的一些主要組件在Web應用中的作用。
上圖精煉的描述了MVC模型以及Java EE的部分組件如何分佈在一個Web應用上,下文所提到的圖示均指該圖。
Web應用
在開始一切之前要瞭解什麼是Web應用,對於圖中最左側的用戶來說,Web應用就是瀏覽器上的一組網頁,這組網頁可以根據自己的操作,包括點擊、輸入等,來動態地展示信息。
這裡的動態意味著,用戶的操作被提交到了後臺的伺服器上進行了某種處理,之後伺服器返回了一些信息對展示在瀏覽器上的網頁進行了更新,從而達到動態效果,所以說,一個單純的HTML靜態頁並不能算是Web應用,哪怕這個頁面被CSS與JavaScript加上了一些視覺上的動態效果。
常見的購物網站比如淘寶,就屬於Web應用,用戶在網站上通過點擊操作不斷的向後臺的伺服器提交著數據,然後動態地更新著瀏覽的商品信息,最後還要鍵入密碼完成剁手。
所以對於用戶來說,後臺的一切就是黑盒,不需要用戶做任何關心,只要提交操作,就能得到結果。
下麵的任務就是瞭解Java EE如何使這個黑盒運轉起來。
MVC模型
可以試想這樣一種情況,用戶想買一把吉他,於是在淘寶的搜索框里輸入”吉他“,然後點擊搜索,期待著頁面能夠刷新並展示出滿是商品的頁面供自己挑選,這時請求提交到後臺伺服器上後,伺服器上只運行著一個helloworld.java程式來處理全部這些操作(也就是說黑盒中只有一個.java文件),這時helloworld.java需要做什麼呢,首先要解析提交進來的數據,使用特定的方法分析這些數據的意思,發現是想要請求一個羅列了吉他商品的新頁面,於是連接到資料庫,請求吉他相關的各種數據,然後使用特定的方法生成一個全新的頁面,最後反饋給瀏覽器,如果用戶提交的是另外的請求,則還需要其他特定的方法來處理,用戶每進行一次任意的操作,helloworld.java就要把這些操作再重新進行一遍。
可以看到這樣的操作十分繁瑣,效率極其低下,耦合度非常高,整個過程中無論是用戶請求、業務邏輯或是頁面結構,只要稍作更改,helloworld.java文件就要重新改寫,完全無法維護。
MVC模型可以很好的處理這個問題,與之前的單一java文件相比,MVC把黑盒分成了三個部分:
- Controller:
如圖所示,用戶提交請求後,到達後端的第一站即是Controller,他對原始的HTTP的Get或Post請求進行解析,得到真正的用戶數據,然後交給Model來處理,這樣Model完全不用關心數據如何解析的問題,也負責把Model返回來的數據封裝起來,提交給View,讓View去更新用戶的頁面。 - Model:
Model從Controller處拿到純凈的數據,專心地依據業務邏輯來處理這些數據,在必要時與資料庫交互,最終把處理完成的數據返回給Controller。 - View:
View從Controller處獲取更新的數據,用這些數據來動態的更新用戶看到的界面。
JSP
MVC中的View可以使用JSP頁面來動態地更新用戶看到的網頁界面,JSP頁面可以理解為一個既可以展示常規的HTML頁面,同時又能夠執行Java代碼的頁面,如果它不執行Java代碼,那效果和普通HTML毫無二致。
JSP中可以寫入Java代碼,用來提取當前頁面中HTML的節點,然後根據從Controller中接收到的新信息來更新這些節點,讓他們重新顯示,這樣一來就不必每次都刷新整個頁面,只需要更新頁面中那些出現變動的部分
Servlet
MVC中的Controller使用servlet來處理信息,servlet其實就是一個.java文件中實現的一個類,比如叫ControllerServlet類,類中主要重寫了兩個方法,一個是doGet方法,一個是doPost方法,分別用來處理前端提交進來的Get和Post請求,把這些請求中的數據解析出來交給Model來處理,然後把Model返回的結果提交給JSP去更新網頁,一般servlet不會對數據做任何邏輯處理。
EJB
在瞭解EJB前需要首先瞭解JavaBean,一個JavaBean實際就是一個Java 類,這個類主要實現了一些getter和setter方法,用setter方法接受一些數據,然後處理一番,用getter方法返回,譬如如下代碼
public class PersonBean implements java.io.Serializable {
private String name = null;
private double score = 100;
public String getName() {
return name;
}
public void setName(final String value) {
name = value;
}
public double getScore() {
return score;
}
public void setScore(final double value) {
score = value;
}}
這個PersonBean類即是一個JavaBean,它可以接受姓名和分數,以及返回姓名和分數,當然在setScore方法中可以對score做一些邏輯處理,譬如score=sqrt(score)*10,表示對學生的分數開根號再乘10,等等。
可以像下麵這樣來使用它
public class TestPersonBean {
public static void main(String[] args) {
PersonBean person = new PersonBean();
person.setName("張三");
person.setScore(88);
System.out.print(person.getName());
System.out.println(person.getScore());
}}
這種類有著很強的可重用性,使用者拿到一個Bean後就知道可以給它set一些值,然後get到自己想要的值,所以專門起了個JavaBean的名字,Bean在Java中就是可重用組件的一種叫法而已,說到某某Bean時應當意識到這就是一個可重用的Java類而已。
而EJB,即Enterprise JavaBean,顧名思義就是JavaBean的一個擴展,能夠實現更複雜的功能。
在MVC模型中,EJB處於Model的最前端,接受Controller解析出來的數據,EJB包含三類:會話(Session)Bean,實體(Entity)Bean,消息驅動(Message Driven)Bean。
- Session Bean:
Session Bean的Session基本是指Bean與用戶的會話,譬如用戶要完成挑選商品添加到購物車,然後結算的動作,這時購物車就可以用一個所謂的有狀態Session Bean來維持,用以持續關註用戶,看是否有新的物品添加進來,或是有什麼商品被刪除了,購物車中有商品被添加或刪除時,這個Session Bean都會運行相關的方法來處理這些動作,當用戶挑選完成,在檢查過購物車後點擊結算,這個有狀態Session Bean就被清除了,它已經完成了與用戶的會話,而在下一步的結算頁面,則可以啟用一個無狀態Session Bean,無狀態意味著用戶一般只用提交一次請求,比如輸入密碼即可,然後賬單的相關信息如價格、收貨地址、包含物品等等,則一次性提交給這個Session Bean,然後用戶就吃飯去了,這個Session Bean也就不用持續關註用戶而去處理這些賬單信息。 - Entity Bean:
Entity Bean其實就是資料庫中的某張表中的某一行所對應的一個Bean,用來對資料庫間接操作,現在一般用JPA取而代之。 - Message Driven Bean:
MDB可以理解為一個消息監聽器,消息源來自JMS,應當意識到這裡的消息不是指那種長篇大論的信息,而一般是短小的,頻繁的短消息,譬如用戶點擊訂閱了某個雜誌,這時這個訂閱的動作就轉成相應的消息交給JMS,MDB監聽到這個消息後再進行相關動作。
JMS
想象一個新聞門戶網站(這顯然是一個Web應用),它每天發佈新聞後,有其他很多新聞網站也想獲取這些新聞,譬如一些科技類新聞網站會實時關註各大新聞門戶網站的科技板塊,所以這些Web應用間需要互相傳遞消息,而JMS作為一組API扮演了消息傳遞中間件,解決了應用間通訊的問題,當一個Web應用使用了JMS的時候,可以想象成是這個Web應用在自己家門口放了一個郵箱,自己每天願意公開的消息,就放在郵箱里,想要的人可以來隨意取用,這樣一來自己根本不用關心要給誰發消息,那些取用消息的人不需問候就可以直接把消息取走,因為郵箱里的消息都是願意被公開的,而自己如果想看別人的消息,就去查看對方的郵箱即可,一個應用想要關註其他多個應用的消息,只要訂閱這些應用的JMS郵箱即可,這就是JMS的發佈/訂閱模型。
JMS還有點對點模型,交大校務處的網站和交大圖書館的網站互通信息,而這些信息不想讓其他Web應用看到,這時可以使用點對點模型,即只在二者之間維護一個消息隊列,圖書館一有新消息,就把它放在這個消息隊列中,然後去忙自己的,校務處有空就查看隊列,取用隊列中的消息,雙方都不必等著對方來發送或接收消息,消息的發送與接受是非同步的。
之前的MDB就是用來監聽JMS消息郵箱或是JMS消息隊列的Bean。
JPA
在瞭解JPA前需要知道什麼是實體對象,在EJB處理數據的時候往往需要和資料庫交互,比如在教務網站上老師查詢一個學生成績的時候,EJB需要根據學生的姓名學號去查看資料庫里相應的表中的這個學生所對應的那一行,然後取到成績這一列再返回,假如語數外理化史地政生的九個老師都時要修改成績,EJB又需要再查九遍然後去修改,還有其他的很多情況,EJB可能需要頻繁的改動資料庫的表中的某一行,如果每次都查顯然很麻煩,而所謂實體其實就是把這樣一行資料庫的數據映射成為一個Java對象,創建出這樣一個對象後就可以一直對它操作,直到不用的時候再釋放即可,而這樣的Java對象就被稱為實體對象,所以實體的意思其實就是那一行數據所對應的實體,譬如那個被查成績的學生,而JPA就是一種規範,詳細規定了實體類和數據行到底怎麼映射。
如圖中所示,Session Bean為了專心地處理數據,一般不和資料庫直接聯繫,而是通過JPA規範下的實體類來取用數據,這樣以來Session Bean的業務邏輯就能很好的和更加底層的資料庫細節解耦了。
JDBC連接池與JDBC資源
Web應用在更上層的部分,比如JSP部分,有時想要直接與資料庫交互而不通過複雜的EJB,設想JSP中的Java代碼直接使用JDBC訪問了資料庫,在初始化JDBC連接的時候需要輸入資料庫的地址、埠、用戶名、密碼等等與資料庫本身緊密關聯的參數,假如有天資料庫的參數改變了,譬如更換了地址或是密碼,那所有JSP上的代碼都得改,而且由於處在前端的JSP變動非常頻繁,直接用JDBC連接資料庫會造成資料庫頻繁開關,性能損耗極大,所以這樣的調用資料庫方式是難以維護的。
JDBC連接池就是處於JSP與資料庫之間的一個中間件,可以把它想象成一個用來放置JDBC連接的池子,Web應用啟動的時候,連接池向資料庫請求足量的連接並放在池中以供JSP取用,這樣首先解決了JSP與資料庫的耦合問題,JSP根本不需要關心資料庫的地址、埠、用戶名、密碼是什麼,它取用資料庫的數據時只要從連接池裡取出一條或多條連接即可,用完之後把連接歸還到連接池中以便別的JSP再次取用,當資料庫的參數變動的時候,只需要修改連接池的參數即可,前端的JSP不需要做任何改動,此外,連接池中有充足的連接,足夠JSP來取用,所以大大降低了資料庫的開關次數,提高了性能。
JDBC資源則是JSP對JDBC連接池中的連接的具體使用方式,JSP通過引用JDBC資源來使用連接。