servlet原理和生命周期,servlet工作原理和生命周期
终极管理员 知识笔记 70阅读
在JavaWeb中Servlet是基于Java编写的服务器端组件用于处理客户端通常是Web浏览器发送的HTTP请求并生成相应的HTTP响应。Servlet运行在Web服务器上与Web容器如Tomcat进行交互通过Web容器将请求分发给适当的Servlet进行处理。
Servlet提供了一种动态生成和处理Web内容的方式可以接收并解析HTTP请求执行业务逻辑生成HTML、XML或其他格式的响应结果并将其返回给客户端。Servlet可以处理各种不同类型的请求如GET请求、POST请求等并可以访问请求的参数、请求头、会话信息等。

在Java中编写一个Servlet需要继承自javax.servlet.http.HttpServlet类并重写其中的一些方法如doGet()、doPost()等。在这些方法中开发人员可以编写处理请求和生成响应的逻辑。另外Servlet也可以实现一些接口如javax.servlet.Servlet、javax.servlet.Filter等以实现更灵活的功能。
Servlet在JavaWeb开发中扮演着非常重要的角色它可以与数据库进行交互、调用其他Java类库、生成动态内容等。通过Servlet开发人员可以实现Web应用程序中的用户认证、数据查询、数据处理、页面跳转等功能。

需要注意的是使用Servlet开发时通常还会配合使用Web框架如Spring MVC、Struts等来简化开发流程和提供更强大的功能。
Sun公司在这些API中提供一个接口叫做Servlet如果你想开发一个Servlet程序只需要完成两个小步骤 编写一个类实现Servlet接口吧开发好的Java类部署到web服务器中总而言之把实现了Servlet接口的Java程序叫做Servlet
6.2、HelloServlet构建一个Maven项目构建一个空的Maven项目我们从头开始写
打开pom.xml即核心配置文件先配置一些依赖空的项目中pom.xml文件中除非必要并无其他东西因此是没有任何一点依赖的
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.2.1</version> </dependency> </dependencies>
我们在此配置了servlet的一些相关依赖以及jsp的一些相关依赖
依赖本质上是jar包配置相关依赖即在仓库中找到相应的jar包如果报错即仓库中没有该jar包IDEA可能会提醒你安装如果没有则在网上找到相关资源下载并把jar包丢入仓库中
关于Maven父子工程的理解我们一开始创建了一个空的Maven项目(Project)在这个项目中我们还可以创建一些Maven模块(Module)当我们创建了一个名为servlet-01的Maven模块以下我们称之为子项目
父项目的pom.xml中会有
<modules> <module>servlet-01</module> </modules>
子项目的pom.xml中会有
<parent> <groupId>com.Xu</groupId> <artifactId>javaweb-02-servlet</artifactId> <version>1.0-SNAPSHOT</version> </parent>
(如果没有可以手动添加)
父项目中的jar包子项目可以直接使用子项目的父项目无法直接使用即类似于继承
将子Maven项目的结构搭建完整创建java包resource包等忘记的同学可以回头看上面Maven配置的博客
编写一个Servlet程序
编写一个普通类
实现Servlet接口这里我们直接继承HttpServletHttpServlet是Sun公司写好的直接继承不必实现
public class HelloServlet extends HttpServlet
进入HttpServlet的源码发现
public abstract class HttpServlet extends GenericServlet
其同样继承了另一个类GenericServlet再进入源码发现
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable
GenericServlet最终实现了 Servlet接口所以即使是继承HttpServlet同样也是实现Servlet接口
Servlet接口中有几个方法
void init(ServletConfig var1) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; String getServletInfo(); void destroy();
其中最为重要的是service方法查看源码可以发现GenericServlet没有实现该方法而是将其定义为抽象方法
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
在HttpServlet才最终实现了它
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method req.getMethod(); long lastModified; if (method.equals(GET)) { lastModified this.getLastModified(req); if (lastModified -1L) { this.doGet(req, resp); } else { long ifModifiedSince req.getDateHeader(If-Modified-Since); if (ifModifiedSince < lastModified) { this.maybeSetLastModified(resp, lastModified); this.doGet(req, resp); } else { resp.setStatus(304); } } } else if (method.equals(HEAD)) { lastModified this.getLastModified(req); this.maybeSetLastModified(resp, lastModified); this.doHead(req, resp); } else if (method.equals(POST)) { this.doPost(req, resp); } else if (method.equals(PUT)) { this.doPut(req, resp); } else if (method.equals(DELETE)) { this.doDelete(req, resp); } else if (method.equals(OPTIONS)) { this.doOptions(req, resp); } else if (method.equals(TRACE)) { this.doTrace(req, resp); } else { String errMsg lStrings.getString(http.method_not_implemented); Object[] errArgs new Object[]{method}; errMsg MessageFormat.format(errMsg, errArgs); resp.sendError(501, errMsg); } }
当然这其中还有许多方法需要被重写才能完成我们想要的功能
重写doGet方法和doPost方法
public class HelloServlet extends HttpServlet { // 由于get或者post只是请求实现的不同方式可以相互调用业务逻辑都一样 Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ServletOutputStream outputStream resp.getOutputStream(); PrintWriter writer resp.getWriter(); writer.print(Hello, Servlet); } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); }}
编写Servlet的映射
为什么需要映射我们写的是Java程序但是要通过浏览器访问而浏览器需要连接web服务器所以我们需要在web服务中注册我们写的Servlet还需给他一个浏览器能够访问的路径
在web.xml文件中配置
<!--注册Servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.xu.servlet.HelloServlet</servlet-class> </servlet> <!--Servlet的注册请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
配置Tomcat
启动测试
首先进入localhost时是index.jsp页面想要跳转到Servlet页面则需要在域名后补上servlet-mapping的url-name比如在测试中笔者所用的url-name为hello则需要将域名改为localhost:8080/s1/hello如果最终测试过程中遇到跳转到servlet页面时出现404的页面则有可能是application context出现了问题请进入smart tomcat中修改
用项目名称即project的名称本示例中为javaweb-02-servlet
如果遇到跳转到servlet页面时出现500的情况则是因为找不到相应的servlet的jar包因此检查是否环境中配置了servlet的依赖如果有则查看Tomcat的版本
Tomcat 9.x.x版本时依赖中添加servlet的jar包名称为javax.servlet-apiTomcat 10.x.x版本后javax变更为javarta因此查看是否依赖正确如果不会修改则卸载Tomcat 10 安装Tomcat 9到目前为止笔者使用的时Tomcat 10但是在修改依赖时将javax修改为javarta会报错还在查找原因当中如果实在没有办法笔者也只能将Tomcat 10 卸载重新安装Tomcat 9 6.3、Servlet原理 配置servlet想要Tomcat创建servlet实现类就必须让Tomcat知道它在哪因此我们在web.xml中配置servlet时必须给出实现类的全限定类名
<!DOCTYPE web-app PUBLIC -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN ><web-app> <display-name>Archetype Created Web Application</display-name> <!--注册Servlet--> <servlet> <servlet-name>hello</servlet-name> <!--全限定类名--> <servlet-class>com.xu.servlet.HelloServlet</servlet-class> </servlet> <!--Servlet的注册请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping></web-app>
Tomcat会将被配置好的servlet放入HashMap中以待日后使用当浏览器发送相应的请求时Tomcat会在HashMap寻找相应的servlet调用它并完成响应。
而且Tomcat并不会一开始就创建servlet对象而是当浏览器发送相应的请求时才会调用无参构造函数若只有有参构造函数而没有无参构造函数服务器是无法调用的请在写servlet应用类时注意添加无参构造函数去创建servlet对象。
初始化Servlet中有一个方法init(ServletConfig var)它将会完成本Servlet的初始化功能Tomcat在创建完成Servlet的实例化对象后将会立即执行初始化操作
serviceservice是servlet中十分重要的方法当我们发送多次请求时并不会重复创建servlet对象servlet实例化对象只会创建一个也就是说当一个servlet类的实例化对象被创造出来后续发送的请求都是由这个实例化对象进行回应而是会不断调用service方法进行响应比如我们在service方法中加入以下代码
Override public void init() throws ServletException { System.out.println(servlet---->init); } Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println(servlet -----> service); }
在发送多次请求时我们可以发现
servlet初始化操作只执行了一次而service方法则每请求一次便调用一次。
销毁通过调用destroy方法来销毁一个servlet对象一般而言关闭浏览器并不会销毁该servlet实例化对象而是当服务器关闭时才会销毁即一个servlet对象的销毁是tomcat服务器调用其destroy方法来完成的。
servlet生命周期第一次发送请求 → Tomcat创建servlet对象→调用初始化方法init→执行service方法
非首次发送请求→执行service方法
关闭服务器→调用destroy方法