Servlet详解(Servlet源码)

Servlet

Servlet是运行在Web服务器或应用服务器上的小程序,它作为来自Web浏览器或其他HTTP客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。Servlet能够接收来自客户端的基于HTTP协议的请求,并且对请求进行响应。

Servlet是用来处理客户端请求并产生动态网页内容的Java类。

通常Servlet特指HttpServlet,用来接受浏览器的访问请求,浏览器最常用的请求为GET和POST方式,还有其它五种,而HttpServlet分别有七个方法(PUT、DELETE、HEADER、TRACE、OPTION)处理这些类型的请求,另有一个是J2EE不支持的,是CONNECT。Servlet是J2EE规范中的重要成员,是构成WEB的重要组件

Servlet是JavaEE规范中的技术之一,是Java开发中最重要的动态资源之一。

Servlet生命周期

Servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。 Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doGet,doPost等,当服务器决定将实例销毁的时候调用其destroy方法。

Servlet的执行流程

客户端发起请求:客户端(如浏览器)向服务端发起HTTP请求。

服务器解析请求:Tomcat服务器通过解析请求地址(URL),找到对应的web应用,并解析出客户端想访问的web资源。

加载Servlet:如果发现Servlet是第一次访问,服务器就会加载Servlet,创建Servlet对象。

初始化:调用Servlet的init()方法,进行初始化操作。默认情况下,Servlet对象会在第一次被访问的时候初始化,对应的init()方法得到执行,并且只会执行一次。

处理请求:调用Servlet的service()方法处理客户端的请求。每当有一次来自客户端的请求,Tomcat服务器会开启一个新的线程调用service()方法。

响应请求:service()方法执行完后,服务器会响应数据给客户端浏览器。

销毁:当服务器正常关闭时,Servlet对象会被销毁,对应的destroy()方法执行,并且只会执行一次。

Servlet的创建方式

Servlet的创建主要有三种方式:

实现Servlet接口:通过实现Servlet接口,实现所有抽象方法。这种方式支持最大程度的自定义,但通常不推荐,因为需要实现的方法较多。

继承GenericServlet抽象类:GenericServlet实现了Servlet接口,但必须与协议无关。继承此类后,需要重写service()方法,其他方法可以选择重写。这种方式让开发Servlet变得简单,但和HTTP协议无关。

继承HttpServlet抽象类:HttpServlet继承自GenericServlet,并基于HTTP协议进行了封装。继承此类后,需要重写doGet()和doPost()等方法。这种方式表示请求和响应都要和HTTP相关,是最常用的方式。

Servlet的配置方式

Servlet的配置主要有两种方式:

web.xml文件配置:在web应用的web.xml文件中配置Servlet的映射关系。

注解配置:使用@WebServlet注解直接在Servlet类上进行配置,这种方式简化了配置过程,是现代开发中的主流方式。

Servlet的生命周期

Servlet的生命周期从创建开始,直到销毁结束。主要包括以下几个阶段:

加载和实例化:当Servlet容器启动时,或者在请求到达时Servlet容器首次调用Servlet的service()方法时,Servlet容器会加载并实例化Servlet。

初始化:容器调用Servlet的init()方法进行初始化。

请求处理:对于到达的客户端请求,Servlet容器会创建代表请求的HttpServletRequest对象和代表响应的HttpServletResponse对象,然后调用Servlet的service()方法。service()方法会根据请求的方式(GET、POST等)调用相应的doXXX()方法(如doGet()、doPost())。

销毁:当Servlet容器关闭或Web应用被卸载时,Servlet容器会调用Servlet的destroy()方法进行销毁。

Servlet的用途

Servlet主要用于处理客户端的请求,生成动态网页内容,并与后端的数据库或其他应用进行交互。它可以读取客户端发送的显式数据(如HTML表单数据)和隐式数据(如cookies、媒体类型等),处理这些数据,并生成响应发送给客户端。Servlet还可以与Java类库的其他部分进行交互,如通过sockets和RMI机制与applets、数据库或其他软件进行通信。

Servlet的线程安全问题

由于Servlet采用的是单例模式(即Servlet对象从始至终都只会创建一次),而一个浏览器就代表一个线程,多个浏览器就是多线程。因此,当存在成员变量时,多个线程并发访问此变量就容易出现线程安全问题。解决线程安全问题的方案包括:

改变共享属性:将成员变量变成局部变量。

改变可变属性:用final修饰成员变量,使其成为常量。

使用同步锁:虽然可以解决线程安全问题,但会降低Servlet的性能,因此通常不推荐在Servlet中使用同步锁。

实现SingleThreadModel接口:虽然可以让Servlet引擎以单线程模式调用service()方法,但这种方式并不推荐,因为它会降低Servlet的并发处理能力。

综上所述,Servlet是Java Web开发中非常重要的技术之一,它通过处理HTTP请求和响应,实现了Web应用的前后端交互。在使用Servlet时,需要注意其生命周期、配置方式、线程安全问题等方面。

Servlet 源码

Servlet 是 Java EE 中处理服务器端请求和响应的核心组件。通过 Servlet 接口、GenericServlet 类和 HttpServlet 类,我们可以实现各种功能的Servlet应用。HttpServletRequest 和 HttpServletResponse 接口提供了丰富的方法来处理HTTP请求和生成响应。理解这些类和接口的源码和工作原理,有助于开发高效的Web应用程序。
1. Servlet 接口

Servlet 接口是所有 Servlet 的父接口,定义了 Servlet 的生命周期方法:

init(ServletConfig config): 初始化 Servlet 方法。在 Servlet 被实例化后调用一次,用于进行资源初始化。

service(ServletRequest req, ServletResponse res): 处理请求和生成响应的方法。每个请求都会调用该方法。

destroy(): 销毁 Servlet 方法。在服务器卸载 Servlet 时调用,用于进行资源清理。

getServletConfig(): 返回 Servlet 的配置信息。

getServletInfo(): 返回 Servlet 的基本信息,如作者、版本等。

复制代码
public interface Servlet {
    void init(ServletConfig config) throws ServletException;
    ServletConfig getServletConfig();
    void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
    String getServletInfo();
    void destroy();
}

2. GenericServlet 类

GenericServlet 类实现了 Servlet 接口,并简化了实现过程。开发者只需要实现 service 方法。

复制代码
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private transient ServletConfig config;

    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {
    }

    public ServletConfig getServletConfig() {
        return this.config;
    }

    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    public String getServletInfo() {
        return "";
    }

    public void destroy() {
    }
}

3. HttpServlet 类

HttpServlet 类继承了 GenericServlet 类,专门用于处理 HTTP 请求。它定义了多个方法来处理不同的 HTTP 方法(如 GET、POST、PUT、DELETE 等)。

复制代码
public abstract class HttpServlet extends GenericServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method GET is not supported by this URL");
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method POST is not supported by this URL");
    }

    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method PUT is not supported by this URL");
    }

    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method DELETE is not supported by this URL");
    }

    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, OPTIONS");
    }

    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method TRACE is not supported by this URL");
    }

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        if (method.equals("GET")) {
            this.doGet(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 {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method " + method + " is not supported by this URL");
        }
    }

    protected long getLastModified(HttpServletRequest req) {
        return -1L;
    }
}

4. HttpServletRequest 和 HttpServletResponse 接口

HttpServletRequest 和 HttpServletResponse 是两个用于处理 HTTP 请求和响应的接口。
HttpServletRequest:

获取请求参数、头信息、路径信息、会话信息等。

常用方法:getParameter(), getHeader(), getSession(), getMethod(), getRequestURI() 等。

复制代码
public interface HttpServletRequest extends ServletRequest {
    String getAuthType();
    Cookie[] getCookies();
    long getDateHeader(String name);
    String getHeader(String name);
    Enumeration<String> getHeaders(String name);
    Enumeration<String> getHeaderNames();
    int getIntHeader(String name);
    String getMethod();
    String getPathInfo();
    String getPathTranslated();
    String getContextPath();
    String getQueryString();
    String getRemoteUser();
    boolean isUserInRole(String role);
    Principal getUserPrincipal();
    String getRequestedSessionId();
    String getRequestURI();
    StringBuffer getRequestURL();
    String getServletPath();
    HttpSession getSession(boolean create);
    HttpSession getSession();
    String changeSessionId();
    boolean isRequestedSessionIdValid();
    boolean isRequestedSessionIdFromCookie();
    boolean isRequestedSessionIdFromURL();
    boolean isRequestedSessionIdFromUrl();
    boolean authenticate(HttpServletResponse response) throws IOException, ServletException;
    void login(String username, String password) throws ServletException;
    void logout() throws ServletException;
    Collection<Part> getParts() throws IOException, ServletException;
    Part getPart(String name) throws IOException, ServletException;
    <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException;
}

HttpServletResponse:

设置响应状态码、头信息、内容类型,写出响应内容等。

常用方法:setStatus(), setHeader(), setContentType(), getWriter(), getOutputStream() 等。

复制代码
public interface HttpServletResponse extends ServletResponse {
    void addCookie(Cookie cookie);
    boolean containsHeader(String name);
    String encodeURL(String url);
    **加粗样式**String encodeRedirectURL(String url);
    String encodeUrl(String url);
    String encodeRedirectUrl(String url);
    void sendError(int sc, String msg) throws IOException;
    void sendError(int sc) throws IOException;
    void sendRedirect(String location) throws IOException;
    void setDateHeader(String name, long date);
    void addDateHeader(String name, long date);
    void setHeader(String name, String value);
    void addHeader(String name, String value);
    void setIntHeader(String name, int value);
    void addIntHeader(String name, int value);
    void setStatus(int sc);
    void setStatus(int sc, String sm);
    int getStatus();
    String getHeader(String name);
    Collection<String> getHeaders(String name);
    Collection<String> getHeaderNames();
    void setContentType(String type);
}

5. 示例:自定义Servlet

以下是一个简单的自定义Servlet示例:

复制代码
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        out.println("<html><body>");
        out.println("<h1>Hello, Servlet!</h1>");
        out.println("</body></html>");
    }
}

在这个示例中,我们创建了一个简单的Servlet,处理GET请求并返回一个HTML页面。

相关推荐
Archy_Wang_11 天前
ASP.NET Core 应用的零停机部署策略
后端·servlet·asp.net
linmengmeng_13143 天前
【Jenkins】Jenkins配置从节点 - Launch Agent
运维·servlet·jenkins
musenh4 天前
servlet入门
servlet
wfsm5 天前
flowable使用01
java·前端·servlet
六件套是我6 天前
redission实现延时队列
android·java·servlet
非典型代码7 天前
Jenkins发不出邮件
运维·servlet·jenkins
佐杰7 天前
Jenkins安装部署
运维·servlet·jenkins
chxii8 天前
Spring Boot 中,内嵌的 Servlet 容器(也称为嵌入式 Web 服务器)
spring boot·servlet
BUG?不,是彩蛋!8 天前
Maven-Java 项目到底解决了什么痛点?
java·servlet·maven
CS Beginner12 天前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis