Java web 面试题
什么是Servlet?
狹義的 Servlet 是指 Java 語言實現(xiàn)的一個接口,廣義的 Servlet 是指任何實現(xiàn)了這個 Servlet 接口的類,一般情況下,人們將 Servlet 理解為后者。
Servlet運行于支持 Java 的應(yīng)用服務(wù)器中。WEB 容器才是與客戶端直接打交道的家伙,它監(jiān)聽了端口,請求過來后,根據(jù) url 等信息,確定要將請求交給哪個 Servlet 去處理,然后調(diào)用那個 Servlet 的 service 方法,service 方法根據(jù)客戶端的請求方式調(diào)用 do××() 方法,最后 WEB 容器再把這個請求的響應(yīng)返回給客戶端。
說一下Servlet的體系結(jié)構(gòu)。
所有的Servlet都必須要實現(xiàn)的核心的接口是javax.servlet.Servlet。每一個Servlet都必須要直接或者是間接實現(xiàn)這個接口,或者是繼承javax.servlet.GenericServlet或者javax.servlet.http.HTTPServlet。最后,Servlet使用多線程可以并行的為多個請求服務(wù)。
Servlet 接口:定義了一個Servlet 應(yīng)該具有的方法 (如 init、service 與 destroy 方法等),所有的Servlet都應(yīng)該直接或間接實現(xiàn)此接口。
GenericServlet 抽象類:通用Servlet,對Servlet 接口的默認實現(xiàn),這是一個抽象類,其中的大部分方法都做了默認實現(xiàn),只有service() 方法是一個抽象方法需要繼承者自己實現(xiàn)。
HttpServlet 抽象類:對 HTTP 協(xié)議進行了優(yōu)化的Servlet,繼承自GenericServlet 類,并且實現(xiàn)了其中的service() 抽象方法,默認的實現(xiàn)中判斷了請求的請求方式,并根據(jù)請求方式的不同分別調(diào)用不同的doXX() 方法。通常我們編寫Servlet 直接繼承該抽象類即可。
解釋下Servlet的生命周期。
加載Servlet 類,創(chuàng)建該類的實例。每一個用戶都會產(chǎn)生一個新的線程 (所以說Servlet 是線程不安全的)
Servlet 通過init() 方法進行初始化
Servlet 調(diào)用service(req,resp) 方法,根據(jù)請求方式調(diào)用對應(yīng)的do××() 方法,來處理客戶端的請求
Servlet 通過destroy() 方法終止
Servlet 被 JVM 的垃圾回收機制收集
Servlet是線程安全的嗎
不是,Servlet 在第一次被加載的時候創(chuàng)建,創(chuàng)建后就一直駐留在 WEb 容器為后續(xù)的請求提供服務(wù),所以Servlet 默認是單例的。這也意味著在多線程的環(huán)境下會產(chǎn)生安全性問題。最好的解決辦法就是不要在 Servlet 中創(chuàng)建實例變量。
這個問題可關(guān)聯(lián)到 SpringMVC 中的 Controller 是否是線程安全的,原理是類似的。
doGet()方法和doPost()方法有什么區(qū)別?
- GET 方法是默認的瀏覽器向 Web 服務(wù)傳遞信息的方法,它會產(chǎn)生一個 很長的字符串,出現(xiàn)在瀏覽器的地址欄中。而 POST 方式則是把數(shù)據(jù)作為一個單獨的消息以標(biāo)準(zhǔn)輸出的形式傳到后臺程序,所以使用 POST 不會將數(shù)據(jù)顯示在地址欄中。
- 對于 GET 方式,服務(wù)端用 Request,QueryString 獲取變量的值;對于 POST 方式,服務(wù)端使用 Request,Form 獲取提交的數(shù)據(jù)。
- GET 方式受傳輸數(shù)據(jù)字節(jié)的限制,POST 方式不受限制。
PS:
關(guān)于上面這些知識點我以前寫了一篇博文 ,有興趣的可以看一下。
HTTP 響應(yīng)的結(jié)構(gòu)是怎么樣的?
- 狀態(tài)行 (Status Code):描述了響應(yīng)的狀態(tài)??梢杂脕頇z查是否成功的完成了請求。請求失敗的情況下,狀態(tài)碼可用來找出失敗的原因。
- HTTP 頭部 (HTTP Header):它們包含了更多關(guān)于響應(yīng)的信息。比如:頭部可以指定認為響應(yīng)過期的過期日期,或者是指定用來給用戶安全的傳輸實體內(nèi)容的編碼格式。
- 主體 (Body):它包含了響應(yīng)的內(nèi)容。它可以包含 HTML 代碼,圖片,等等。主體是由傳輸在 HTTP 消息中緊跟在頭部后面的數(shù)據(jù)字節(jié)組成的。
HTTP 協(xié)議 是非常重要的協(xié)議,理解了 HTTP 協(xié)議能解決好多疑問。
sendRedirect()和forward()方法有什么區(qū)別?
- sendRedirect()重定向:客戶端發(fā)送兩次請求,重定向 (redirect) 以后,之前請求作用域范圍以內(nèi)的對象就失效了,因為會產(chǎn)生一個新的請求,地址欄也會發(fā)生變化。
- forward()轉(zhuǎn)發(fā):客戶端只發(fā)送一次請求,轉(zhuǎn)發(fā) (forwarding) 以后,之前請求作用域范圍以內(nèi)的對象仍然可以訪問,地址欄不會發(fā)生變化。
什么是 URL 編碼和 URL 解碼?
URL 編碼是負責(zé)把 URL 里面的空格和其他的特殊字符替換成對應(yīng)的十六進制表示,反之就是解碼。
- 可以用URLEncoder.encoder(String url,String encoder)方法進行 URL 編碼
- 用URLDecoder.decode(String url,String encoder)方法進行 URL 解碼
JSP 請求是如何被處理的?
瀏覽器首先要請求一個以.jsp擴展名結(jié)尾的頁面,發(fā)起 JSP 請求,然后,Web 服務(wù)器讀取這個請求,使用 JSP 編譯器把 JSP 頁面轉(zhuǎn)化成一個Servlet類。
需要注意的是,只有當(dāng)?shù)谝淮握埱箜撁婊蛘呤?JSP 文件發(fā)生改變的時候 JSP 文件才會被編譯,然后服務(wù)器調(diào)用Servlet類,處理瀏覽器的請求。一旦請求執(zhí)行結(jié)束,Servlet會把響應(yīng)發(fā)送給客戶端。
jdk動態(tài)代理與CGLIB動態(tài)代理的區(qū)別
jdk 動態(tài)代理:jdk 中的動態(tài)代理是通過反射類 Proxy 以及 InvocationHandler 回調(diào)接口實現(xiàn)的。有一點需要注意的是,被代理的對象必須是接口的實現(xiàn)類,也就是說只能對該類所有實現(xiàn)接口的方法進行動態(tài)織入,因此存在著一定的局限性。
CGLIB 動態(tài)代理:CGLIB 會動態(tài)的為一個類生成一個代理的子類,子類重寫要代理的類的所有不是 final 的方法。在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,順勢織入橫切邏輯。因為 CGLIB 使用字節(jié)碼處理框架 ASM,來轉(zhuǎn)換字節(jié)碼并生成新的類,所以它比使用 java 反射的 jdk 動態(tài)代理要快。
Spring IoC 容器的優(yōu)點
IoC 容器把對象的依賴關(guān)系有序的建立起來,簡化了對象依賴關(guān)系的管理,在很大程度上簡化了面向?qū)ο笙到y(tǒng)的復(fù)雜性。
IoC 容器可以把資源的獲取方向反轉(zhuǎn),讓 IoC 容器主動管理這些依賴關(guān)系,將這些關(guān)系注入到組件中,可以使依賴關(guān)系的適配和管理變得更加靈活。
如果合作對象的引用或依賴關(guān)系的管理由具體對象來完成,會導(dǎo)致代碼的高度耦合和可測試性降低,這對復(fù)雜的面向?qū)ο笙到y(tǒng)的設(shè)計是非常不利的。有了 IoC 容器之后,這些依賴關(guān)系可以通過把對象的依賴注入交給框架或者 IoC 容器來完成,這種從具體對象手中交出控制的做法是非常有價值的,它可以在解耦代碼的同時提高代碼的可測試性。
總結(jié)
以上是生活随笔為你收集整理的Java web 面试题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 玻璃瓶调味料盖子怎么去掉?
- 下一篇: Python入门:正则表达式