深入了解tomcat中servlet的創(chuàng)建方式實(shí)現(xiàn)
一、 什么是servlet
1.1、用官方的話解釋:
Servlet是oracle公司提供的一門用于開(kāi)發(fā)動(dòng)態(tài)web資源的技術(shù),屬于javaEE體系中的一種核心規(guī)范。
通俗解釋一下:就是我們開(kāi)發(fā)人員所編寫(xiě)的一個(gè)類,必須直接或者間接實(shí)現(xiàn)這個(gè)javaEE的核心規(guī)范,也就是實(shí)現(xiàn)Servlet接口,因?yàn)檫@種類產(chǎn)生的對(duì)象可以被瀏覽器訪問(wèn)到,因此稱之為Servlet,并且javaEE中規(guī)定了只有Servlet的實(shí)現(xiàn)類產(chǎn)生的對(duì)象才可以被瀏覽器訪問(wèn),就是Servlet.(也就是說(shuō)這個(gè)類要直接或者間接實(shí)現(xiàn)了Servlet接口)
二、開(kāi)始進(jìn)入servlet的創(chuàng)建
2.1、通過(guò)前面介紹,我們知道了一個(gè)什么樣的類創(chuàng)建的對(duì)象可以被瀏覽器訪問(wèn),首先我們直接上代碼:
package com.briup.web; import java.io.IOException; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class FirstWay implements Servlet { public FirstWay() { System.out.println("對(duì)象創(chuàng)建了"); } @Override public void init(ServletConfig config) throws ServletException { // TODO Auto-generated method stub System.out.println("我是init:我被調(diào)用了"); } @Override public ServletConfig getServletConfig() { // TODO Auto-generated method stub return null; } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { // TODO Auto-generated method stub System.out.println("我是service,我被調(diào)用了"); } @Override public String getServletInfo() { // TODO Auto-generated method stub return null; } @Override public void destroy() { // TODO Auto-generated method stub System.out.println("我是destory:我被調(diào)用了"); } }
那么,一個(gè)滿足servlet的類已經(jīng)創(chuàng)建好了,接下來(lái)拋出疑問(wèn)
servet對(duì)象由誰(shuí)創(chuàng)建?
里面實(shí)現(xiàn)的接口方法,哪些會(huì)調(diào)用,什么時(shí)候調(diào)用,調(diào)用幾次?
第一個(gè)疑問(wèn): 既然是servlet類,由我們開(kāi)發(fā)人員自己手動(dòng)創(chuàng)建對(duì)象,顯然是不合理,所以這個(gè)對(duì)象的創(chuàng)建,是交給tomcat創(chuàng)建的,我們開(kāi)發(fā)人員只需要告訴 tomcat,讓他創(chuàng)建,讓他什么時(shí)候創(chuàng)建就行了;
如何告訴?
1、方法一:通過(guò)配置webxml的方式。(極其不推薦使用)
對(duì)于整個(gè)動(dòng)態(tài)web項(xiàng)目而言,web.xml是最先加載的配置文件,所以在web.xml的方式配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>firstWay</display-name> <servlet> <servlet-name>FirstWay</servlet-name> <servlet-class>com.briup.web.FirstWay</servlet-class> <!-- <load-on-startup>1</load-on-startup> --> </servlet> <servlet-mapping> <servlet-name>FirstWay</servlet-name> <url-pattern>/FirstWay</url-pattern> </servlet-mapping> </web-app>
解釋:
1、servlet-name:見(jiàn)名知意:servlet的名字,注意要與下面你設(shè)置映射的名字對(duì)應(yīng)
2、serlvet-class:serlvet的全限定名
3、load-on-startup:是否在tomcat啟動(dòng)的時(shí)候就創(chuàng)建servlet對(duì)象,傳入一個(gè)大于0的整數(shù)‘'(默認(rèn)是瀏覽器第一次請(qǐng)求的時(shí)候創(chuàng)建servlet對(duì)象)
4、servlet-mapping:見(jiàn)名知意,設(shè)置瀏覽器的訪問(wèn)映射
5、servlet-name:于上面的對(duì)應(yīng)
6、url-pattern:瀏覽器的訪問(wèn)映射(假設(shè)默認(rèn)是本機(jī)的話,且tomcat的端口號(hào)為8080,那么瀏覽器訪問(wèn)這個(gè)servlet的路徑為:localhost:8080/項(xiàng)目名/FirstWay)
有了這些基礎(chǔ),讓我們?cè)L問(wèn)看看;
第一步:啟動(dòng)tomcat
tomcat正常啟動(dòng)
第二步:通過(guò)瀏覽器訪問(wèn)(我們這里手動(dòng)訪問(wèn)3次)
瀏覽器訪問(wèn)正常
第三步:觀察控制臺(tái)
通過(guò)運(yùn)行結(jié)果分析:
第一次啟動(dòng)服務(wù)器,對(duì)象并沒(méi)有被創(chuàng)建
瀏覽器請(qǐng)求三遍,但是對(duì)象只創(chuàng)建一次,init()方法也只調(diào)用一次
每訪問(wèn)一次,對(duì)象便會(huì)調(diào)用一次service()方法
其他方法沒(méi)被調(diào)用
解釋為嘛沒(méi)被調(diào)用:getServletConfig():得到ServletConfig對(duì)象
: getServletInfo():得到Servlet的信心,比如作者
:destroy():servlet銷毀的時(shí)候才會(huì)調(diào)用這個(gè)方法,(比如:tomcati正常關(guān)閉 這里我就不去測(cè)試,想測(cè)試的小伙伴,可以右鍵service,點(diǎn)擊stop)然后再觀察控制臺(tái)便可知了。
2、方法二:注解的方式告訴tomcat(與前者相比,推薦使用)
@WebServlet(value ="映射路徑") public Fristservlet implement Servelt { }
通過(guò)這個(gè)注解也可以設(shè)置,是否在啟動(dòng)服務(wù)器的時(shí)候就創(chuàng)建對(duì)象,這里就不演示了,
注意:(一旦使用了注解的方式告訴tomcat如果創(chuàng)建某個(gè)對(duì)象,就不能在web.xml里面再對(duì)這個(gè)servlet進(jìn)行訪問(wèn)設(shè)置了)
三、回歸主題,servlet的第二種創(chuàng)建方式
有了前面的解釋,直接上代碼然后再分析
package com.briup.web; import java.io.IOException; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; @WebServlet(value = "/secondWay") public class SecondWayCreate extends GenericServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { // TODO Auto-generated method stub System.out.println("調(diào)用了service方法"); } }
1、比第一種方法簡(jiǎn)潔,實(shí)現(xiàn)的是GenericServlet這個(gè)類
2、我們看一下GenericServlet源碼,然后進(jìn)行分析;
public abstract class GenericServlet implements Servlet, ServletConfig,
可知,這是個(gè)抽線類,是servlet接口的實(shí)現(xiàn)類,那么GenericServlet間接 實(shí)現(xiàn)了servlet接口,
與第一種方式相比:開(kāi)發(fā)者不是必須將一些接口中不必要的方法實(shí)現(xiàn),可以具有選擇性,減少了代碼量。然而并沒(méi)有上面ruan用,就是裝b而已
三、重點(diǎn)第三種方式(與前兩者相比,我更推薦第三種方式)
直接上代碼
package com.briup.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(value = "/ThreeWayCreate") public class ThreeWayCreate extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doPost(req, resp); } }
通過(guò)以上代碼,可能就有小伙伴要問(wèn)了
不是說(shuō)servlet要直接或者間接實(shí)現(xiàn)servlet接口嗎,不是說(shuō)瀏覽器每請(qǐng)求一次就要調(diào)用一次service方法嗎?方法在哪呢?這不是與前面理論沖突了嗎?
我們繼續(xù)看源碼,源碼才是道理
我在下面值列舉源碼里面比較核心的部分,需要理解更加深入了解的小伙伴,直接去看源碼,tomcat是開(kāi)源的
package com.briup.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(value = "/ThreeWayCreate") public class ThreeWayCreate extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doPost(req, resp); } }
分析:
第一步分析
可知這個(gè)抽象類繼承了GennericeServlet這個(gè)抽象類 也就是逐層往下推,實(shí)現(xiàn)了Servle接口,那么這個(gè)抽線類必然也繼承了serice方法。
第二步分析
這個(gè)是繼承servlet接口的service方法,當(dāng)瀏覽器每請(qǐng)求一次時(shí),都會(huì)調(diào)用這個(gè)方法,由圖可知,這個(gè)方法已經(jīng)被HttpServlet實(shí)現(xiàn)了,由實(shí)現(xiàn)類可以得出,請(qǐng)求對(duì)象req,和響應(yīng)對(duì)象res,被強(qiáng)轉(zhuǎn)成了HttpServletRequest,和HttpServletResponse(向下轉(zhuǎn)型),然后將強(qiáng)轉(zhuǎn)的對(duì)象,傳入HttpServlet重載的Service方法中,調(diào)用,第三步,分析重載后的Service(HttpRequest req,HttpRespone res);
第三步分析
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // Invalid date header - proceed as if none was set ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
通過(guò)傳過(guò)來(lái)的HttpRequest對(duì)象,判斷請(qǐng)求方式,通過(guò)請(qǐng)求方式,決定調(diào)用哪個(gè)方法(如果請(qǐng)求方式是post方式,那么就會(huì)調(diào)用doPost(HttpRequest req,HttpRestpone Res)方法)
第四步分析
綜上分析,總結(jié):tomcat創(chuàng)建對(duì)象,當(dāng)瀏覽器請(qǐng)求的時(shí)候,調(diào)用Servlet的Service(ServeltRequest req,ServletRespone res )方法,然后這個(gè)方法再調(diào)用,HttpServlet里面重載的Servlet(HttpServletReqeust req ,HttpServletRespone res)方法,然后這個(gè)方法會(huì)通過(guò)請(qǐng)求方式是什么,選擇性的調(diào)用doPost(),還是doGet()方法(當(dāng)然還有很多其他的方式這里就不列舉了), 因此第三種方式,的本質(zhì)還是當(dāng)瀏覽器發(fā)起一次請(qǐng)求的時(shí)候調(diào)用了Servlet接口里面的Service(ServeltRequest req,ServletRespone res )方法,然后通過(guò)實(shí)現(xiàn)類的里面的邏輯,間接的調(diào)用了doPost()等方法。
優(yōu)點(diǎn):
1、通過(guò)請(qǐng)求方式可以處理相應(yīng)的請(qǐng)求,使得邏輯更加清晰
2,減少代碼量,是程序更加簡(jiǎn)潔
3,使得請(qǐng)求或者響應(yīng)的操作性更加豐富
4…
四、 總結(jié):
注意點(diǎn):瀏覽器發(fā)起請(qǐng)求調(diào)用的一定是servlet種的service方法;
到此這篇關(guān)于深入了解tomcat中servlet的創(chuàng)建方式實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)tomcat servlet創(chuàng)建方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 使用IDEA創(chuàng)建servlet?JavaWeb?應(yīng)用及使用Tomcat本地部署的實(shí)現(xiàn)
- IDEA2021 tomcat10 servlet 較新版本踩坑問(wèn)題
- tomcat關(guān)于配置servlet的url-pattern的問(wèn)題思路詳解
- 詳解Tomcat是如何實(shí)現(xiàn)異步Servlet的
- 詳解如何通過(guò)tomcat的ManagerServlet遠(yuǎn)程部署項(xiàng)目
- Tomcat怎么實(shí)現(xiàn)異步Servlet
- tomcat中Servlet的工作機(jī)制詳細(xì)介紹
- Tomcat架構(gòu)設(shè)計(jì)及Servlet作用規(guī)范講解
相關(guān)文章
centos環(huán)境下使用tomcat 部署SpringBoot的war包
這篇文章主要介紹了centos環(huán)境下使用tomcat 部署SpringBoot的war包的相關(guān)資料,本文通過(guò)實(shí)例代碼給大家講解的很詳細(xì),對(duì)tomcat 部署SpringBoot 的war包相關(guān)知識(shí)感興趣的朋友一起看看吧2021-05-05Tomcat弱口令復(fù)現(xiàn)及利用(反彈shell)
本文主要介紹了Tomcat弱口令復(fù)現(xiàn)及利用(反彈shell),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05tomcat+nginx實(shí)現(xiàn)多應(yīng)用部署的示例代碼
本文主要介紹了tomcat+nginx實(shí)現(xiàn)多應(yīng)用部署的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11Tomcat 多站點(diǎn)配置詳解及實(shí)現(xiàn)方法
這篇文章主要介紹了Tomcat 多站點(diǎn)配置詳解及實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2016-12-12Tomcat啟動(dòng)成功但無(wú)法訪問(wèn)http://localhost:8080/的解決方法
在初次使用Tomcat時(shí)遇到了一些問(wèn)題,經(jīng)過(guò)一段時(shí)間的調(diào)試最終將其解決,個(gè)人感覺(jué)此問(wèn)題應(yīng)該比較常見(jiàn),因此在這做一個(gè)分享,這篇文章主要給大家介紹了關(guān)于Tomcat啟動(dòng)成功但無(wú)法訪問(wèn)http://localhost:8080/的解決方法,需要的朋友可以參考下2023-04-04Tomcat HTTPS證書(shū)申請(qǐng)與部署的實(shí)現(xiàn)
本文主要介紹了Tomcat HTTPS證書(shū)申請(qǐng)與部署的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06