如今許許多多的初學者和程序員,都在趨之若鶩地學習Web開發的寶典級框架:Struts2,Spring,Hibernate。彷佛這些框架成爲了一我的是否精通Java,是否會寫J2EE程序的惟一事實標準和找工做的必備基礎。然而,若是在面試的時候問這些程序員,大家爲何要學習這些框架?這些框架的本質究竟是什麼?彷佛不多不多有人可以給我很是滿意的答覆。由於他們都在爲了學習而學習,爲了工做而學習,而不是在真正去深刻了解一個框架。其實全部的人都應該思考這樣的問題:爲何要學習框架?框架到底給我帶來了什麼?接下來,咱們以登陸做爲一個最簡單的例子,來看看不一樣的年代,咱們是怎麼寫Web程序的。後來,咱們放棄了在頁面上寫邏輯。後來,程序寫得愈來愈多,咱們發現,這種在HTML代碼中編寫Java代碼來完成邏輯的方式存在着很多問題:java
1.Java代碼因爲混雜在一個HTML環境中而顯得混亂不堪,可讀性很是差。一個JSP文件有時候會變成幾十K,甚至上百K。要找一段邏輯,常常沒法定位。程序員
2. 編寫代碼時很是困惑,不知道代碼到底應該寫在哪裏,也不知作別人是否是已經曾經實現過相似的功能,到哪裏去引用。web
3. 忽然之間,某個需求發生了變化。因而,每一個人矇頭開始全程替換,還要當心翼翼的,生怕把別人的邏輯改了。面試
4. 邏輯處理程序須要本身來維護生命週期,對於相似數據庫事務、日誌等衆多模塊沒法統一支持。數據庫
在這個時候,若是有一個產品,它可以將頁面上的那些Java代碼抽取出來,讓頁面上儘可能少出現Java代碼,該有多好。因而許多人開始使用servlet來處理那些業務邏輯。app
public class LoginServlet extends HttpServlet { /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String message = null; RequestDispatcher dispatcher = req.getRequestDispatcher("/result.jsp"); String name = req.getParameter("name"); String password = req.getParameter("password"); UserHandler userHandler = new UserHandler(); if(userHandler.authenticate(name, password)) { message = "恭喜你,登陸成功"; } else { message = "對不起,登陸失敗"; } req.setAttribute("message", message); dispatcher.forward(req, resp); } }
在這裏,咱們須要在web.xml中爲這個servlet配置url的請求關係。 框架
<servlet> <servlet-name>Login</servlet-name> <servlet-class> com.demo2do.servlet.LoginServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>Login</servlet-name> <url-pattern> /Login </url-pattern> </servlet-mapping>
代碼重構到這裏,咱們發現,其實咱們的工做量自己並無減小,只是代碼從JSP移動到了Servlet,使得整個流程看上去稍微清楚了一些。然而,爲了這麼點乾淨,咱們付出的代價是什麼?爲每一個servlet都在web.xml裏面去作一個url的請求配置!jsp
在不少年前,咱們這麼寫程序的。不少年前,那是一個貧苦的年代,若是咱們要使用Java在網頁上作一些動態的交互功能。不少人會告訴你一個技術,叫作JSP。在我還對Java很是困惑的時候,就有人告訴我,JSP是個好東西,它能夠在HTML代碼裏面寫Java代碼來完成邏輯。ide
<% String name = request.getParameter("name"); String password = request.getParameter("password"); UserHandler userHandler = new UserHandler(); if(userHandler.authenticate(name, password)) { %> <p>恭喜你,登陸成功</p> <% } else { %> <p>對不起,登陸失敗</p> <% } %>
做爲一張JSP,它能夠接收從別的JSP發送過來的登陸請求,並進行處理。這樣,咱們不須要任何額外的配置文件,也不須要任何框架的幫忙,就能完成邏輯。再後來,出現框架。時代進一步發展,人們發現簡單的JSP和Servlet已經很難知足人們懶惰的要求了。因而,人們開始試圖總結一些公用的Java類,來解決Web開發過程當中碰到的問題。這時,橫空出世了一個框架,叫作struts。它很是先進地實現了MVC模式,成爲了廣大程序員的福音。學習
struts的代碼示例我就不貼了,網上隨便搜搜你能夠發現一堆一堆的。在必定程度上,struts可以解決web開發中的職責分配問題,使得顯示與邏輯分開。不過在很長一段時間內,使用struts的程序員每每沒法分別咱們到底須要web框架幫咱們作什麼,咱們到底須要它完成點什麼功能?咱們到底要什麼?在回顧了咱們寫代碼的歷史以後,咱們回過頭來看看,咱們到底要什麼?
不管是使用JSP,仍是使用Struts1,或是Struts2,咱們至少都須要一些必須的元素(若是沒有這些元素,或許我還真不知道這個程序會寫成什麼樣子):
1. 數據在這個例子中,就是name和password。他們共同構成了程序的核心載體。事實上,咱們每每會有一個User類來封裝name和password,這樣會使得咱們的程序更加OO。不管怎麼說,數據會穿插在這個程序的各處,成爲程序運行的核心。
2.頁面展現在這個例子中,就是login.jsp。沒有這個頁面,一切的請求、驗證和錯誤展現也無從談起。在頁面上,咱們須要利用HTML,把咱們須要展示的數據都呈現出來。同時咱們也須要完成必定的頁面邏輯,例如,錯誤展現,分支判斷等等。
3.處理具體業務的場所在這裏,不一樣階段,處理具體業務的場所就不太同樣。原來用JSP和Servlet,後來用Struts1或者Struts2的Action。
上面的這些必須出現的元素,在不一樣的年代,被賦予了不一樣的表現形式,有的受到時代的束縛,其表現形式很是落後,有的已經再也不使用。可是撥開這些外在的表現形式,咱們就能夠發現,這不就是咱們已經熟門熟路的MVC嘛?
數據 —— Model,頁面展現 —— View,處理具體業務的場所 —— Control
因此,框架不重要,概念是王道。只要可以深入理解MVC的概念,框架對你來講,只是一個jar包而已。
MVC的概念其實就那麼簡單,這些概念其實早已深刻咱們的心裏,而咱們所缺少的是將其本質挖掘出來。咱們來看看下面這幅圖,這是一副流行了不少年的講述MVC模型的圖:
在這幅圖中,MVC三個框框各司其職,結構清晰明朗。不過我以爲這幅圖忽略了一個問題,就是數據是動的,數據在View和Control層一旦動起來,就會產生許多的問題:
1. 數據從View層傳遞到Control層,如何使得一個個扁平的字符串,轉化成一個個生龍活虎的Java對象。
2. 數據從View層傳遞到Control層,如何方便的進行數據格式和內容的校驗?
3. 數據從Control層傳遞到View層,一個個生龍活虎的Java對象,又如何在頁面上以各類各樣的形式展示出來。
4.若是你試圖將數據請求從View層發送到Control層,你如何才能知道你要調用的到底是哪一個類,哪一個方法?一個Http的請求,又如何與Control層的Java代碼創建起關係來?除此以外,Control層彷佛也沒有想象中的那麼簡單,由於它做爲一個控制器,至少還須要處理如下的問題:
1. 做爲調用邏輯處理程序的facade門面,若是邏輯處理程序發生了異常,咱們該如何處理?
2. 對於邏輯處理的結果,咱們須要作怎麼樣的處理才能知足豐富的前臺展現須要?
這一個又一個問題的提出,都基於對MVC的基本概念的挖掘。因此,這些問題都須要咱們在寫程序的時候去一一解決。說到這裏,這篇文章開頭所提的問題應該能夠有答案了:框架是爲了解決一個又一個在Web開發中所遇到的問題而誕生的。不一樣的框架,都是爲了解決不一樣的問題,可是對於程序員而言,他們只是jar包而已。框架的優缺點的評論,也徹底取決於其對問題解決程度和解決方式的優雅性的評論。因此,千萬不要爲了學習框架而學習框架,而是要爲了解決問題而學習框架,這纔是一個程序員的正確學習之道。