天天看點

Java 面試知識點解析(七)——Web篇

  • 前言:

在遨遊了一番 Java Web 的世界之後,發現了自己的一些缺失,是以就着一篇深度好文:知名網際網路公司校招 Java 開發崗面試知識點解析 ,來好好的對 Java 知識點進行複習和學習一番,大部分内容參照自這一篇文章,有一些自己補充的,也算是重新學習一下 Java 吧。

前序文章連結:

Java 面試知識點解析(一)——基礎知識篇

Java 面試知識點解析(二)——高并發程式設計篇

Java 面試知識點解析(三)——JVM篇

Java 面試知識點解析(四)——版本特性篇

Java 面試知識點解析(五)——網絡協定篇

Java 面試知識點解析(六)——資料庫篇

(一)J2EE 相關知識點

不涉及任何架構,對 J2EE 相關知識點的解析

1)Servlet 的生命周期?

在 Web 容器中,Servlet 主要經曆 4 個階段,如下圖:

1. 加載 Servlet:當 Tomcat 第一次通路 Servlet 的時候,Tomcat 會負責建立 Servlet 的執行個體。

2. 初始化 Servlet:當 Servlet 被執行個體化之後,Tomcat 會調用 init() 方法來初始化這個對象。

3. 處理服務:當浏覽器通路 Servlet 的時候,Servlet 會調用 service() 方法處理請求。

4. 銷毀:當 Tomcat 關閉或者檢測到 Servlet 要從 Tomcat 删除的時候,會自動調用 destroy() 方法,讓該執行個體所占用的資源釋放掉。一個 Servlet 如果長時間不被使用的話,也會被 Tomcat 自動銷毀。

  • 簡單總結:隻要通路 Servlet ,就會調用其對應的 service() 方法,init() 方法隻會在第一次通路 Serlvet 的時候才會被調用。

2)Servlet 的請求流程?

  1. 浏覽器送出請求:

    http://localhost:80/xxx1/xxx2

    (80端口可以預設不寫,因為這是http協定預設的端口,平時我們通路

    https://www.baidu.com/

    時其實通路的是

    https://www.baidu.com:80/

  2. 伺服器解析請求資訊:
    • http:協定名稱
    • localhost:通路的是網際網路中的哪一台計算機
    • 80:從主機當中找到對應 80 端口的程式 (這裡即為 Tomcat 伺服器)
    • /xxx1:目前項目的上下文路徑 (即在 server.xml 中配置主機時配置的 path屬性)
    • /xxx2:目前請求的資源名
  3. 解析 Tomcat 伺服器根目錄下的 /config/server.xml 檔案:

    <Context docBase="D:\javaPros\test\webapp" path="xxx1" />

    判斷哪一個

    <Context />

    元素的 path屬性 屬性為

    xxx1

    • 若找不到,則傳回 404錯誤
    • 若找到了,則解析該

      <Context />

      元素,得到

      docBase

      屬性,擷取目前通路 Web 項目的跟的絕對路徑:

      D:\javaPros\test\webapp

  4. D:\javaPros\test\webapp

    下的 WEB-INF 下找到 web.xml 檔案

    判斷 web.xml 檔案中是否有

    <url-pattern>

    的文本内容為 /xxx2
    • 若找到了,則繼續擷取該資源對應 Servlet 類的全限名稱: xxx.xxx
  5. 判斷 Servlet 執行個體緩存池 中是否有 xxx.xxx 的對象
Map<String,Servlet> cache = ......(Tomcat提供的);
	key:存Servlet類的全限定名稱
	value:該Servlet類的對象.
Servlet obj = cache.get("xxx.xxx");
	if(obj==null){
		//Servlet執行個體緩存中沒有該類的對象,第一次.
		GOTO 6:
	}else{
		//有對象,非第一次.
		GOTO 8:
	}
}
           
  1. 使用反射調用構造器,建立對應的對象

    obj = Class.forName("xxx.xxx").newInstance();

    把目前建立的 Servlet 對象,存放在緩存之中,供給下一次的使用.

    cache.put("xxx.xxx",obj);

  2. 建立 ServletConfig 對象,并調用 init() 方法

    obj.init(config);

  3. 建立 ServletRequest 對象和 ServletResponse 對象,并調用 service()方法

    obj.service(req,resp);

  4. 在 service() 方法中對浏覽器作出響應操作。

3)Servlet 是單例的嗎?為什麼?

Servlet 是單例的,浏覽器多次對Servlet的請求,一般情況下,伺服器隻建立一個Servlet對象,也就是說,Servlet對象一旦建立了,就會駐留在記憶體中,為後續的請求做服務,直到伺服器關閉。

4)GET 和 POST 的差別

要知道,GET 和 POST 都是請求方式

1. GET:

浏覽器器位址欄:

http://localhost/test.html?name=wmyskxz&sex=male

這裡送出了兩個參數,一個是

name

屬性值為

wmyskxz

,另一個是

sex

male

,這是一種直接的請求方式,在請求資源後面跟上 ? 符号與參數連接配接,其他的參數使用 & 符号連接配接。

  • 缺點:

    1.暴露請求資訊,不安全

    2.請求資訊不能超過1kb,可傳輸的資訊有限,不能上傳圖檔

2. POST:

浏覽器位址欄:

http://localhost/test.html#

  • 優點:

    1.隐藏了請求資訊,較安全(但仍可以通過相關工具通路到資料)

    2.POST 方式沒有限制請求的資料大小,可以做圖檔的上傳

5)Tomcat 中如何解決中文亂碼問題?

在 Tomcat 伺服器中,接受請求的時候,預設的編碼方式為 ISO-8859-1,而該編碼方式隻占一個位元組,不支援中文(兩個位元組),是以當我們做請求的時候,會出現亂碼的問題

解決方案:

1.對亂碼使用 ISO-8859-1 解碼,轉換成byte數組,恢複為二進制

byte[] data = name.getBytes("ISO-8859-1");

2.對byte數組重新進行 UTF-8 編碼:

name = new String(data,"UTF-8");

但是這樣會出現一個問題,那就是當表單資料太多的時候,這樣反複解碼-編碼,會很繁瑣。

終極解決方案:

1.對于 POST 請求:

設定請求的編碼方式:

request.setCharacterEncoding("UTF-8");

注意:必須在擷取第一個參數之前設定,并且該方式隻對 POST 方式有效。

2.對于 GET 請求:

重新設定 Tomcat 的編碼方式,修改 Tomcat 的配置檔案:

Tomcat根目錄/conf/server.xml(修改端口的那一行)

6)forward 與 redirect 的差別

1.請求轉發(forward)

又叫做直接轉發方式,用戶端和浏覽器隻發出一次請求,Servlet、HTML、JSP或其它資訊資源,由第二個資訊資源響應該請求,在請求對象request中,儲存的對象對于每個資訊資源是共享的。

比如:從 AServlet 請求轉發到 BServlet

  • 文法:
request.getRequestDispatcher(path).forward(request, response);
           

參數:

path

,要跳轉到的資源路徑:上下文路徑 / 資源路徑

特點:

1.位址欄中的位址【不會】改變,通常看作是服務端的跳轉

2.隻有一個請求

3.資源是共享的

也就是說在兩個 Servlet 中可以共享請求的資源,可以通過

request.setAttribute(String var1,Object var2)

設定要共享的資料資源,并通過

request.getAttribute(String var1);

來擷取傳遞的資源

4.【可以】通路 WEB-INF 中的資源

WEB-INF 檔案夾是 Java Web 應用的預設安全目錄,即用戶端無法直接通路,隻有服務端可以通路的目錄。如果想在頁面中直接通路其中的檔案,必須通過web.xml檔案對要通路的檔案進行相應映射才能通路。

注意:在實際的開發中,可以把不希望使用者直接通路到(通過浏覽器輸入位址欄)的網頁放在檔案夾中通過此方式通路。

5.請求轉發【不能】跨域通路

所謂的同域,是指域名,協定,端口均相同

2.URl 重定向(redirect)

又叫做間接轉發方式(Redirect)實際是兩次HTTP請求,伺服器端在響應第一次請求的時候,讓浏覽器再向另外一個URL送出請求,進而達到轉發的目的。

比如:從AServlet重定向到BServlet

response.sendRedirect(String location);
           

location

,轉發到的資源路徑

1.位址欄中的位址【會】發生改變,通常看作是用戶端跳轉

2.有兩個請求

3.在兩個 Servlet 中不可以共享請求中的資料

4.最終的響應由 BServlet 來決定,和 AServlet 沒有關系

5.【不可以】通路 WEB-INF 中的資源

6.請求轉發【能】跨域通路

就像是在網頁中點開了新的連結一樣

  • 總結:URL 重定向相當于是将重定向的資源路徑,重新複制到浏覽器位址欄中按下回車一樣,重新發送一次新的請求。

7)JSP 的執行原理?

當通路一個 JSP 頁面時,該頁面請求将會講給伺服器中的 JSP 引擎去處理,它負責解釋和執行 JSP 頁面,每個 JSP 頁面在第一次被通路時,JSP 引擎就會将它翻譯成一個繼承自

org.apache.jasper.runtime.HttpJspBase

類的 Servlet 源程式,接着再編譯成 class 類檔案,再由 Web 容器像調用普通 Servlet 程式一樣的方式來裝載和解釋執行這個由 JSP 頁面翻譯成的 Servlet 程式。

8)request.getAttribute() 和 request.getParameter() 有何差別?

  1. request.getParameter() 通常用來接收接收表單的get或者post送出過來的參數;而request.getAttribute()一般和setAttribute()搭配使用,隻有先set之後才能通過get方法擷取到Object類型的資料
  2. getAttribute 傳回的是對象,而getParameter 傳回的是字元串
  3. getAttribute 和 setAttribute 隻是在 web 容器内流轉,僅僅是請求處理階段;而 getParameter 取到的資料是通過容器來擷取的。

9)JSP 與 Servlet 的差別?

  1. JSP 實質上就是一個 Servlet。可以了解為,JSP 是編譯後的 “Servlet 類”;
  2. JSP 由 HTML 代碼和 JSP 标簽組成,更擅長頁面顯示;而 Servlet 更擅長流程控制;
  3. JSP 感覺像是 HTML 中嵌入 Java 代碼,而 Servlet 有些像 Java 中嵌入 HTML 代碼的意思。

10)JSP 靜态包含和動态包含的差別?

(1)靜态包含:編譯指令包含

<%@include file="被包含的頁面的路徑"%>

包含的時機:在 JSP 檔案被翻譯的時候合并在一起,最終翻譯得到一個 class檔案

(2)動态包含:動作指令包含

<jsp:include page="被包含頁面的路徑"></jsp:include>

包含的時機:在運作階段合并代碼,最終得到兩個 class 檔案

(3)動态包含和靜态包含的選擇:

  • 如果被包含的頁面如果是靜态頁面,那麼使用靜态包含;
  • 如果被包含的如果是動态頁面,那麼使用動态包含。

11)JSP 有哪些内置對象?作用分别是什麼?

JSP 共有以下 9 個内置的對象:

  1. request:使用者端請求,此請求會包含來自 GET/POST 請求的參數;
  2. response:表示一次響應對象;
  3. pageContext:表示目前的 JSP 對象;
  4. session:表示一次會話對象;
  5. application:表示目前應用對象;
  6. out:表示一個輸出流對象;
  7. config:表示目前 JSP 的配置對象;
  8. page:表示目前頁面;
  9. exception:表示異常對象。

12)JSTL 是什麼?優點有哪些?

JSTL(JSP StandardTagLibrary,JSP标準标簽庫)是一個不斷完善的開放源代碼的JSP标簽庫,由四個定制标記庫(core、format、xml和sql)和一對通用标記庫驗證器(ScriptFreeTLV和PermittedTaglibsTLV)組成。優點有:

  1. 在應用程式伺服器之間提供了一緻的接口,最大程式地提高了WEB應用在各應用伺服器之間的移植。
  2. 簡化了JSP和WEB應用程式的開發。
  3. 以一種統一的方式減少了JSP中的scriptlet代碼數量,可以達到沒有任何scriptlet代碼的程式。在我們公司的項目中是不允許有任何的scriptlet代碼出現在JSP中。
  4. 允許JSP設計工具與WEB應用程式開發的進一步內建。相信不久就會有支援JSTL的IDE開發工具出現。

13)什麼是 Cookie?Session 和 Cookie 有什麼差別?

Cookie 技術

Cookie 是一種會話技術,用于将使用者的資訊儲存在用戶端上。Cookie 英文直接翻譯過來就是小甜品,Cookie 的作用呢,通俗的說就是當一個使用者通過 HTTP 通路一個伺服器時,這個伺服器會将一些 Key/Value 鍵值對傳回給用戶端浏覽器,并給這些資料加上一些限制條件,在條件符合時這個使用者下次通路這個伺服器時,資料又被完整地帶回給伺服器。

這個作用就像是你去超市購物時,第一次給你辦了一張購物卡,在這個購物卡裡存放了一些你的個人資訊,下次你再來這個超市的時候,你就隻需要帶上你的購物卡,直接購物就好了。

Session 技術

Session:會話,從浏覽器打開開始,直到浏覽器關閉結束,無論在這個網站中通路了多少頁面,點選了多少連結,都屬于同一個會話。Session 也可以稱為會話 Cookie

  • 特點:服務端技術,将資料儲存在伺服器

Cookie 與 Session 的差別

  • Cookie 的資料是存放在客戶的浏覽器上,Session 資料放在伺服器上;
  • Cookie 不是很安全,别人可以分析存放在本地的 Cookie 并進行 Cookie 欺騙,如果考慮安全問題則應當使用 Session;
  • Session 會在一定時間内儲存在伺服器上,當通路增多,會比較占用伺服器的資源,是以如果考慮性能問題,則應當使用 Cookie;
  • 單個 Cookie 在用戶端的限制是 3k ,就是說一個站點在用戶端存放的 Cookie 不能超過 3k。

總結: 将登入資訊等重要資訊存放為 Session;其他資訊如果需要保留,可以存放在 Cookie 中。

14)什麼是過濾器?

過濾器就是 Servlet 的進階特性之一,就是一個具有攔截/過濾功能的一個東西,在生活中過濾器可以是香煙濾嘴,濾紙,淨水器,空氣淨化器等,在 Web 中僅僅是一個實作了 Filter 接口的 Java 類而已。

  • 特點:雙向,攔截請求,攔截響應
  • 作用:

    過濾器可以對所有的請求或者響應做攔截操作

15)為什麼在 Web 開發中需要用到過濾器?

  • 問題:為什麼非得使用過濾器,我直接在 Servlet 中作判斷不行嗎?
  • 開發遵循的原則:

    1.DRY原則(Don't Reeat Yourself,不要重複你自己):重複,意味着維護的成本很高。

    2.責任分離原則:誰擅長什麼功能就做什麼功能,Servlet 擅長的是邏輯而不是處理請求

舉一個實際的例子:(處理 POST 請求中文編碼的問題)

  • Web 中過濾器的作用:

    1.可以在請求資源之前設定請求的編碼

    2.可以進行登入校驗

    3.可以進行請求參數的内容的過濾

    4.資料壓縮 / 資料加密 / 資料格式的轉換

    5.可以設定浏覽器相關的資料

16)MVC 模式?

MVC模式(Model-View-Controller)是軟體工程中的一種軟體架構模式,把軟體系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller):

  • Controller——負責轉發請求,對請求進行處理
  • View——負責界面顯示
  • Model——業務功能編寫(例如算法實作)、資料庫設計以及資料存取操作實作

在JSP/Servlet開發的軟體系統中,這三個部分的描述如下所示:

1.Web浏覽器發送HTTP請求到服務端,被Controller(Servlet)擷取并進行處理(例如參數解析、請求轉發)

2.Controller(Servlet)調用核心業務邏輯——Model部分,獲得結果

3.Controller(Servlet)将邏輯處理結果交給View(JSP),動态輸出HTML内容

4.動态生成的HTML内容傳回到浏覽器顯示

MVC模式在Web開發中的好處是非常明顯,它規避了JSP與Servlet各自的短闆,Servlet隻負責業務邏輯而不會通過out.append()動态生成HTML代碼;JSP中也不會充斥着大量的業務代碼。這大大提高了代碼的可讀性和可維護性。

  • 參考:知乎@David

(二)架構相關知識

由于我沒有接觸和學習過 Hibernate 和 Struts 這兩個架構,是以細節方面的東西請讀者自行收集...

1)什麼是架構?

架構是指完成一定功能的半成品。

架構能夠幫助我們完成的是:項目的整體架構、一些基礎功能、規定了類和對象如何建立,如何協作等,當我們開發一個項目時,架構幫助我們完成了一部分功能,我們自己再完成一部分,那這個項目就完成了。

2)什麼是 Spring ?

  1. Spring 是一個輕量級的 DI / IoC 和 AOP 容器的開源架構,來源于 Rod Johnson 在其著作《Expert one on one J2EE design and development》中闡述的部分理念和原型衍生而來。
  2. Spring 提倡以 “最少侵入” 的方式來管理應用中的代碼,這意味着我們可以随時安裝或者解除安裝 Spring
  • 适用範圍:任何 Java 應用
  • Spring 的根本使命:簡化 Java 開發

3)什麼是非侵入式設計?

從架構的角度可以了解為:無需繼承架構提供的任何類

這樣我們在更換架構時,之前寫過的代碼幾乎可以繼續使用。

4)Spring 有什麼優勢?

  • 低侵入 / 低耦合 (降低元件之間的耦合度,實作軟體各層之間的解耦)
  • 聲明式事務管理(基于切面和慣例)
  • 友善內建其他架構(如MyBatis、Hibernate)
  • 降低 Java 開發難度
  • Spring 架構中包括了 J2EE 三層的每一層的解決方案(一站式)

Spring 的架構結構

  • Data Access/Integration層包含有JDBC、ORM、OXM、JMS和Transaction子產品。
  • Web層包含了Web、Web-Servlet、WebSocket、Web-Porlet子產品。
  • AOP子產品提供了一個符合AOP聯盟标準的面向切面程式設計的實作。
  • Core Container(核心容器):包含有Beans、Core、Context和SpEL子產品。
  • Test子產品支援使用JUnit和TestNG對Spring元件進行測試。

5)Spring IoC 和 DI 分别是什麼?

Spring IoC

IoC:Inverse of Control(控制反轉),讀作 “反轉控制”,更好了解,不是什麼技術,而是一種設計思想,就是将原本在程式中手動建立對象的控制權,交由Spring架構來管理。

  • 正控:若要使用某個對象,需要自己去負責對象的建立
  • 反控:若要使用某個對象,隻需要從 Spring 容器中擷取需要使用的對象,不關心對象的建立過程,也就是把建立對象的控制權反轉給了Spring架構
  • 好萊塢法則:Don’t call me ,I’ll call you

為了便于了解我們這裡舉一個鮮明的例子:

在現實生活中,人們要用到一樣東西的時候,第一反應就是去找到這件東西,比如想喝新鮮橙汁,在沒有飲品店的日子裡,最直覺的做法就是:買果汁機、買橙子,然後準備開水。值得注意的是:這些都是你自己“主動”創造的過程,也就是說一杯橙汁需要你自己創造。

然而到了今時今日,由于飲品店的盛行,當我們想喝橙汁時,第一想法就轉換成了找到飲品店的聯系方式,通過電話等管道描述你的需要、位址、聯系方式等,下訂單等待,過一會兒就會有人送來橙汁了。

請注意你并沒有“主動”去創造橙汁,橙汁是由飲品店創造的,而不是你,然而也完全達到了你的要求,甚至比你創造的要好上那麼一些。

  • 總結: 這就是一種控制反轉的理念,上述的例子已經很好的說明了問題,我們再來描述一下控制反轉的概念:控制反轉是一種通過描述(在 Java 中可以是 XML 或者注解)并通過第三方(Spring)去産生或擷取特定對象的方式。
  • 好處: ① 降低對象之間的耦合;② 我們不需要了解一個類的具體實作,隻需要知道它有什麼用就好了(直接向 IoC 容器拿)

DI:Dependency Injection(依賴注入)

指 Spring 建立對象的過程中,将對象依賴屬性(簡單值,集合,對象)通過配置設值給該對象

兩者的差別

IoC 和 DI 其實是同一個概念的不同角度描述,DI 相對 IoC 而言,明确描述了 “被注入對象依賴 IoC 容器配置依賴對象”。

你也可以簡單的了解為:IoC 是目的,是一種思想,而 DI 是手段,是一種設計模式。

6)BeanFactory 和 ApplicationContext 的差別

1.BeanFactory:

是Spring中最底層的接口,隻提供了最簡單的IoC功能,負責配置,建立和管理bean。在應用中,一般不使用 BeanFactory,而推薦使ApplicationContext(應用上下文),原因如下。

2.ApplicationContext:

⑴. 繼承了 BeanFactory,擁有了基本的 IoC 功能;

⑵. 除此之外,ApplicationContext 還提供了以下功能:

① 支援國際化;② 支援消息機制;③ 支援統一的資源加載;④ 支援AOP功能;

  • 注意: ApplicationContext 和 BeanFactory 相比,最主要的差別在于 BeanFactory 是延遲加載,舉個例子:如果 Bean 沒有完全注入,BeanFactory 加載後,會在你第一次調用 getBean 方法才會抛出異常;而 ApplicationContext 會在初始化的時候就加載并且檢查,這樣的好處是可以及時檢查依賴是否完全注入;是以通常我們會選擇 ApplicationContext。

7)IoC 是如何實作的

最後我們簡單說說IoC是如何實作的。想象一下如果我們自己來實作這個依賴注入的功能,我們怎麼來做? 無外乎:

  1. 讀取标注或者配置檔案,看看JuiceMaker依賴的是哪個Source,拿到類名
  2. 使用反射的API,基于類名執行個體化對應的對象執行個體
  3. 将對象執行個體,通過構造函數或者 setter,傳遞給 JuiceMaker

我們發現其實自己來實作也不是很難,Spring實際也就是這麼做的。這麼看的話其實IoC就是一個工廠模式的更新版!當然要做一個成熟的IoC架構,還是非常多細緻的工作要做,Spring不僅提供了一個已經成為業界标準的Java IoC架構,還提供了更多強大的功能,是以大家就别去造輪子啦!希望了解IoC更多實作細節不妨通過學習Spring的源碼來加深了解!

引用位址:這裡

8)Spring 配置 Bean 有幾種方式?

在 Spring 中提供了 3 種方法進行配置:

  • 在 XML 檔案中顯式配置
  • 在 Java 的接口和類中實作配置
  • 隐式 Bean 的發現機制和自動裝配原則

方式選擇的原則

在現實的工作中,這 3 種方式都會被用到,并且在學習和工作之中常常混合使用,是以這裡給出一些關于這 3 種優先級的建議:

1.最優先:通過隐式 Bean 的發現機制和自動裝配的原則。

基于約定由于配置的原則,這種方式應該是最優先的

  • 好處:減少程式開發者的決定權,簡單又不失靈活。

2.其次:Java 接口和類中配置實作配置

在沒有辦法使用自動裝配原則的情況下應該優先考慮此類方法

  • 好處:避免 XML 配置的泛濫,也更為容易。
  • 典型場景:一個父類有多個子類,比如學生類有兩個子類,一個男學生類和女學生類,通過 IoC 容器初始化一個學生類,容器将無法知道使用哪個子類去初始化,這個時候可以使用 Java 的注解配置去指定。

3.最後:XML 方式配置

在上述方法都無法使用的情況下,那麼也隻能選擇 XML 配置的方式。

  • 好處:簡單易懂(當然,特别是對于初學者)
  • 典型場景:當使用第三方類的時候,有些類并不是我們開發的,我們無法修改裡面的代碼,這個時候就通過 XML 的方式配置使用了。

9)介紹一下 Spring AOP

AOP 即 Aspect Oriented Program 面向切面程式設計

首先,在面向切面程式設計的思想裡面,把功能分為核心業務功能,和周邊功能。

  • 所謂的核心業務,比如登陸,增加資料,删除資料都叫核心業務
  • 所謂的周邊功能,比如性能統計,日志,事務管理等等

周邊功能在 Spring 的面向切面程式設計AOP思想裡,即被定義為切面

在面向切面程式設計AOP的思想裡面,核心業務功能和切面功能分别獨立進行開發,然後把切面功能和核心業務功能 "編織" 在一起,這就叫 AOP

還是來舉一個鮮明的例子:

在上面的例子中,包租婆的核心業務就是簽合同,收房租,那麼這就夠了,灰色框起來的部分都是重複且邊緣的事,交給中介商就好了,這就是 AOP 的一個思想:讓關注點代碼與業務代碼分離!

10)Spring 中 Bean 的作用域

在預設的情況下,Spring IoC 容器隻會對一個 Bean 建立一個執行個體,但有時候,我們希望能夠通過 Spring IoC 容器擷取多個執行個體,我們可以通過

@Scope

注解或者

<bean>

元素中的

scope

屬性來設定,例如:

// XML 中設定作用域
<bean id="" class="" scope="prototype" />
// 使用注解設定作用域
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
           

Spring 提供了 5 種作用域,它會根據情況來決定是否生成新的對象:

作用域類别 描述
singleton(單例) 在Spring IoC容器中僅存在一個Bean執行個體 (預設的scope)
prototype(多例) 每次從容器中調用Bean時,都傳回一個新的執行個體,即每次調用getBean()時 ,相當于執行new XxxBean():不會在容器啟動時建立對象
request(請求) 用于web開發,将Bean放入request範圍 ,request.setAttribute("xxx") , 在同一個request 獲得同一個Bean
session(會話) 用于web開發,将Bean 放入Session範圍,在同一個Session 獲得同一個Bean
globalSession(全局會話) 一般用于 Porlet 應用環境 , 分布式系統存在全局 session 概念(單點登入),如果不是 porlet 環境,globalSession 等同于 Session

在開發中主要使用

scope="singleton"

scope="prototype"

,對于MVC中的Action使用prototype類型,其他使用singleton,Spring容器會管理 Action 對象的建立,此時把 Action 的作用域設定為 prototype.

擴充閱讀:@Profile 注解 、 條件化裝配 Bean

11)Spring 面試問答 Top 25

更多戳這裡:Spring面試問答Top 25

12)Spring MVC 的請求流程

每當使用者在 Web 浏覽器中點選連結或者送出表單的時候,請求就開始工作了,像是郵差一樣,從離開浏覽器開始到擷取響應傳回,它會經曆很多站點,在每一個站點都會留下一些資訊同時也會帶上其他資訊,下圖為 Spring MVC 的請求流程:

第一站:DispatcherServlet

從請求離開浏覽器以後,第一站到達的就是 DispatcherServlet,看名字這是一個 Servlet,通過 J2EE 的學習,我們知道 Servlet 可以攔截并處理 HTTP 請求,DispatcherServlet 會攔截所有的請求,并且将這些請求發送給 Spring MVC 控制器。

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <!-- 攔截所有的請求 -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
           
  • DispatcherServlet 的任務就是攔截請求發送給 Spring MVC 控制器。

第二站:處理器映射(HandlerMapping)

  • 問題:典型的應用程式中可能會有多個控制器,這些請求到底應該發給哪一個控制器呢?

是以 DispatcherServlet 會查詢一個或多個處理器映射來确定請求的下一站在哪裡,處理器映射會根據請求所攜帶的 URL 資訊來進行決策,例如上面的例子中,我們通過配置 simpleUrlHandlerMapping 來将 /hello 位址交給 helloController 處理:

<bean id="simpleUrlHandlerMapping"
      class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <!-- /hello 路徑的請求交給 id 為 helloController 的控制器處理-->
            <prop key="/hello">helloController</prop>
        </props>
    </property>
</bean>
<bean id="helloController" class="controller.HelloController"></bean>
           

第三站:控制器

一旦選擇了合适的控制器, DispatcherServlet 會将請求發送給選中的控制器,到了控制器,請求會卸下其負載(使用者送出的請求)等待控制器處理完這些資訊:

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
	// 處理邏輯
    ....
}
           

第四站:傳回 DispatcherServlet

當控制器在完成邏輯處理後,通常會産生一些資訊,這些資訊就是需要傳回給使用者并在浏覽器上顯示的資訊,它們被稱為模型(Model)。僅僅傳回原始的資訊時不夠的——這些資訊需要以使用者友好的方式進行格式化,一般會是 HTML,是以,資訊需要發送給一個視圖(view),通常會是 JSP。

控制器所做的最後一件事就是将模型資料打包,并且表示出用于渲染輸出的視圖名(邏輯視圖名)。它接下來會将請求連同模型和視圖名發送回 DispatcherServlet。

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
	// 處理邏輯
    ....
    // 傳回給 DispatcherServlet
	return mav;
}
           

第五站:視圖解析器

這樣以來,控制器就不會和特定的視圖相耦合,傳遞給 DispatcherServlet 的視圖名并不直接表示某個特定的 JSP。(實際上,它甚至不能确定視圖就是 JSP)相反,它傳遞的僅僅是一個邏輯名稱,這個名稱将會用來查找産生結果的真正視圖。

DispatcherServlet 将會使用視圖解析器(view resolver)來将邏輯視圖名比對為一個特定的視圖實作,它可能是也可能不是 JSP

上面的例子是直接綁定到了 index.jsp 視圖

第六站:視圖

既然 DispatcherServlet 已經知道由哪個視圖渲染結果了,那請求的任務基本上也就完成了。

它的最後一站是視圖的實作,在這裡它傳遞模型資料,請求的任務也就完成了。視圖使用模型資料渲染出結果,這個輸出結果會通過響應對象傳遞給用戶端。

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" isELIgnored="false"%>

<h1>${message}</h1>
           
更多 Spring-MVC 内容:Spring MVC【入門】就這一篇

13)什麼是 ORM?

對象關系映射(Object-Relational Mapping,簡稱ORM)是一種為了解決程式的面向對象模型與資料庫的關系模型互不比對問題的技術;

簡單的說,ORM是通過使用描述對象和資料庫之間映射的中繼資料(在Java中可以用XML或者是注解),将程式中的對象自動持久化到關系資料庫中或者将關系資料庫表中的行轉換成Java對象,其本質上就是将資料從一種形式轉換到另外一種形式。

14)為什麼要使用 MyBatis ?

在我們傳統的 JDBC 中,我們除了需要自己提供 SQL 外,還必須操作 Connection、Statment、ResultSet,不僅如此,為了通路不同的表,不同字段的資料,我們需要些很多雷同模闆化的代碼,閑的繁瑣又枯燥。

而我們在使用了 MyBatis 之後,隻需要提供 SQL 語句就好了,其餘的諸如:建立連接配接、操作 Statment、ResultSet,處理 JDBC 相關異常等等都可以交給 MyBatis 去處理,我們的關注點于是可以就此集中在 SQL 語句上,關注在增删改查這些操作層面上。

并且 MyBatis 支援使用簡單的 XML 或注解來配置和映射原生資訊,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成資料庫中的記錄。

15)MyBatis 中占位符

#

$

的差別

差別如下:

  1. #

    符号将傳入的資料都當做一個字元串,會對自動傳入的資料加一個雙引号
  2. $

    符号将傳入的資料直接顯示生成SQL中。
  3. #

    符号存在預編譯的過程,,對問号指派,防止SQL注入。
  4. $

    符号是直譯的方式,一般用在orderby {列名} 語句中。
  5. 能用

    #

    号就不要用

    $

    符号

16)MyBatis 緩存結構

在 Web 系統中,最重要的操作就是查詢資料庫中的資料。但是有些時候查詢資料的頻率非常高,這是很耗費資料庫資源的,往往會導緻資料庫查詢效率極低,影響客戶的操作體驗。于是我們可以将一些變動不大且通路頻率高的資料,放置在一個緩存容器中,使用者下一次查詢時就從緩存容器中擷取結果。

  • MyBatis 擁有自己的緩存結構,可以用來緩解資料庫壓力,加快查詢速度。
  • MyBatis 一級緩存是一個 SqlSession 級别,同一個 SqlSession 隻能通路自己的一級緩存的資料
  • 二級緩存是跨sqlSession,是 mapper 級别的緩存,對于 mapper 級别的緩存不同的sqlsession是可以共享的。
更多深入MyBatis的内容戳這裡:MyBatis(2)——MyBatis 深入學習

17)MyBatis 與 Spring 整合

戳這裡:MyBatis 與 Spring 整合

18)IDEA 整合 SSM 架構學習

戳這裡IDEA 整合 SSM 架構學習

19)MVC 三種模式

在早期 Java Web 的開發中,統一把顯示層、控制層、資料層的操作全部交給 JSP 或者 JavaBean 來進行處理,我們稱之為 Model1:

  • 出現的弊端:
  • JSP 和 Java Bean 之間嚴重耦合,Java 代碼和 HTML 代碼也耦合在了一起
  • 要求開發者不僅要掌握 Java ,還要有高超的前端水準
  • 前端和後端互相依賴,前端需要等待後端完成,後端也依賴前端完成,才能進行有效的測試
  • 代碼難以複用

正因為上面的種種弊端,是以很快這種方式就被 Servlet + JSP + Java Bean 所替代了,早期的 MVC 模型(Model2)就像下圖這樣:

首先使用者的請求會到達 Servlet,然後根據請求調用相應的 Java Bean,并把所有的顯示結果交給 JSP 去完成,這樣的模式我們就稱為 MVC 模式。

  • M 代表 模型(Model)

    模型是什麼呢? 模型就是資料,就是 dao,bean

  • V 代表 視圖(View)

    視圖是什麼呢? 就是網頁, JSP,用來展示模型中的資料

  • C 代表 控制器(controller)

    控制器是什麼? 控制器的作用就是把不同的資料(Model),顯示在不同的視圖(View)上,Servlet 扮演的就是這樣的角色。

擴充閱讀:Web開發模式

Spring MVC 的架構

為解決持久層中一直未處理好的資料庫事務的程式設計,又為了迎合 NoSQL 的強勢崛起,Spring MVC 給出了方案:

傳統的模型層被拆分為了業務層(Service)和資料通路層(DAO,Data Access Object)。在 Service 下可以通過 Spring 的聲明式事務操作資料通路層,而在業務層上還允許我們通路 NoSQL ,這樣就能夠滿足異軍突起的 NoSQL 的使用了,它可以大大提高網際網路系統的性能。

  • 結構松散,幾乎可以在 Spring MVC 中使用各類視圖

    松耦合,各個子產品分離

    與 Spring 無縫內建

20)分頁?

戳這裡:Java Web -【分頁功能】詳解

21)什麼是 Spring Boot ?

  • 它使用 “習慣優于配置” (項目中存在大量的配置,此外還内置一個習慣性的配置,讓你無須)的理念讓你的項目快速運作起來。
  • 它并不是什麼新的架構,而是預設配置了很多架構的使用方式,就像 Maven 整合了所有的 jar 包一樣,Spring Boot 整合了所有架構(引自:springboot(一):入門篇——純潔的微笑)

22)使用 Spring Boot 有什麼好處?

回顧我們之前的 SSM 項目,搭建過程還是比較繁瑣的,需要:

  • 1)配置 web.xml,加載 spring 和 spring mvc
  • 2)配置資料庫連接配接、配置日志檔案
  • 3)配置家在配置檔案的讀取,開啟注解
  • 4)配置mapper檔案
  • .....

而使用 Spring Boot 來開發項目則隻需要非常少的幾個配置就可以搭建起來一個 Web 項目,并且利用 IDEA 可以自動生成生成,這簡直是太爽了...

  • 劃重點:簡單、快速、友善地搭建項目;對主流開發架構的無配置內建;極大提高了開發、部署效率。
Spring Boot 由于筆者還沒有深入學習..是以細節部分請讀者自行收集...

歡迎轉載,轉載請注明出處!

簡書ID:@我沒有三顆心髒

github:wmyskxz

歡迎關注公衆微信号:wmyskxz_javaweb

分享自己的Java Web學習之路以及各種Java學習資料

繼續閱讀