Introduction of the Servlet

A Servlet (Server Applet) is a Java Servlet. Is written in Java server-side procedures. Its main function is to interactively browse and modify data to generate dynamic Web content. The narrow sense of Servlet refers to an interface implemented by Java language, and the broad sense of Servlet refers to any class that implements this Servlet interface. Generally, people understand Servlet as the latter. Servlets run in Java-enabled application servers. Implementatively, servlets can respond to any type of request, but most of the time servlets are only used to extend HTTP-based Web servers. The earliest Java Web Server to support the Servlet standard was JavaSoft. Since then, several other Java-based Web servers have begun to support standard servlets.

How to implement servlets

First of all, the Servlet interface is not in the JDK, we need to introduce servlet-API third-party library to find the corresponding interface. X Servlet3.x Servlet4.x dependencies for the latest stable releases of servlet2. x, and any feature updates between the three major releases are explained at the end.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>provided</scope>
</dependency>
Copy the code
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
Copy the code
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
Copy the code

The Servlet needs to inherit HttpServlet and then implement the methods that the parent class uses to handle the request, such as the doGet() doPost() service() method, etc. Here we create a HelloServlet.

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.write("<h1>Hello " + req.getParameter("name") + "</h1>"); writer.flush(); }}Copy the code

The Servlet container reads the web. XML file at startup, finds the Servlet information configured in the file, reflects it, and instantiates it. So it also needs to be configured in web.xml.


      
<! DOCTYPEweb-app
        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <servlet>
        <servlet-name>Controller</servlet-name>
        <servlet-class>com.servlet.learning.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Controller</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>
Copy the code

The above code is packaged as a war format, deployed to tomcat, visit http://localhost:8080/JavaServletLearning/HelloServlet.do? name=nickname

How to Understand servlets

Servlet is an interface in the Javax.servlet.api package javax.servlet.servlet. This interface specifies the things that an application must do when handling network requests, such as initialization, processing business logic, and destruction. The following is the source code comment for the Servlet

package javax.servlet;
import java.io.IOException;

public interface Servlet {

    // Initialization action before processing business logic
    public void init(ServletConfig config) throws ServletException;

    // Get configuration information for the Servlet
    public ServletConfig getServletConfig(a);

    // To execute the business logic, the Servlet container will parse the network request and pass it in as a ServletRequest object
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    public String getServletInfo(a);

    // Destroy after processing the business logic
    public void destroy(a);
}
Copy the code

Why define such an interface? The Servlet interface defines a set of specifications for handling network requests, all Servlet implementation classes must implement these methods, and all Servlet-enabled Web servers call these five methods.

Take Tomcat as an example. Tomcat is a Servlet container. When a browser sends a request, Tomcat first receives the request and determines which Servlet implementation class to handle it based on the URL of the request. The Servlet implementation class’s init() service() destroy() method is then called in turn, and the response result is parsed and returned to the browser.

Other Servlet containers such as Jetty Jboss handle this as well, which is why the same set of code can be deployed on different Web servers that support the Servlet protocol.

Has the Java Servlet API provides two abstract class for developers to achieve their own Servlet, respectively is javax.mail Servlet. GenericServlet and javax.mail Servlet. HTTP. HttpServlet. GenericServlet defines a general and specific network protocol independent Servlet, while HttpServlet defines HttpServlet, we usually inherit HttpServlet to define our own business logic in the development of Web applications. The DispatcherServlet in SpringMvc also inherits from HttpServlet and is secondary encapsulated.

package javax.servlet;

import java.io.IOException;
import java.util.Enumeration;
import java.util.ResourceBundle;

public abstract class GenericServlet implements Servlet.ServletConfig.java.io.Serializable {

    private transient ServletConfig config;

    public GenericServlet(a) {}public void init(a) throws ServletException {}// Set the ServletConfig object during initialization
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    // GenericServlet does not implement the service method, leaving implementation to the following subclasses
    public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    // This method does not destroy the Servlet object, but must be called before the Servlet object is destroyed. We can override this method to do some recycling
    public void destroy(a) {}}Copy the code
package javax.servlet.http;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public abstract class HttpServlet extends GenericServlet implements java.io.Serializable {

    // When implementing our own business logic, it is generally not recommended to override this method because it already does a lot of processing
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    	HttpServletRequest	request;
    	HttpServletResponse	response;
    	try {
    	    request = (HttpServletRequest) req;
    	    response = (HttpServletResponse) res;
    	} catch (ClassCastException e) {
    	    throw new ServletException("non-HTTP request or response");
    	}
    	service(request, response);
    }

    // The real processing logic is here
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod(); // Get the HTTP request type

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < (lastModified / 1000 * 1000)) { // Determine whether the resource has been modified
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); // If not modified, return 304 directly}}// Call different methods for different request types
        } 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 {
            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); Return 504 if no request type is matched}}}Copy the code

Use filters in servlets

Servlet filters can dynamically intercept requests and responses to transform or use the information contained in the request or response. You can attach one or more Servlet filters to a Servlet or set of servlets. Servlet filters can also be attached to JavaServer Pages (JSP) files and HTML Pages. Call all additional Servlet filters before calling the Servlet. Servlet filters are Java classes that can be used for Servlet programming to accomplish the following purposes:

  • Intercepts client requests before they access back-end resources.
  • The server’s responses are processed before they are sent back to the client. First you need to implementFilterInterface, and implements its three methods:
public class BeforeFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("BeforeFilter initializes...");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("BeforeFilter Execution logic...");
        chain.doFilter(request, response);
    }
    @Override
    public void destroy(a) {
        System.out.println("BeforeFilter destroyed..."); }}Copy the code

Unlike servlets, filters are initialized when the container is started, not when a request is received. Now let’s configure the filter to web.xml:

<web-app>
    <! Filters are executed in the same order as they are configured, usually before all servlets are configured.
    <filter>
        <filter-name>BeforeFilter</filter-name>
        <filter-class>com.servlet.learning.BeforeFilter</filter-class>
    </filter>
    <! -- Filter path blocking rule -->
    <filter-mapping>
        <filter-name>BeforeFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
</web-app>
Copy the code

When the container starts, it reads the web.xml file and initializes the filter based on the fully qualified name of the class. It is important to note that after executing the logic in the doFilter() method, the chain-.dofilter (request, response) method must be called to pass the request back to the filter chain.

The life cycle of a Servlet

The Servlet life cycle consists of loading instantiation, initialization, processing client requests, and destruction. Loading and instantiation are primarily done by the Web container, with the next three steps provided by the object’s init() service() destroy() method, respectively.

Initialization: Init () this method is called only once when the Servlet object is created, mainly for initialization purposes. When will the Servlet object be initialized? 1. Some servlets marked < loadStartup >1
in web.xml are automatically initialized when the container starts. 2. The first request received after the Servlet is started. 3. The Servlet class file is updated.

Handling client requests: The Servlet container calls the service() method to handle requests from the client (browser) and returns the results to the client. Each time the Servlet container receives an Http request, the Servlet container spawns a new thread and calls the Servlet instance’s service method, which checks for Http request types (GET, POST, PUT, DELETE, etc.), And call the doGet, doPost, doPut, doDelete methods when appropriate. So, when coding the request processing logic, we just need to focus on the implementation of doGet() or doPost().

Destroy: The destroy() method is called only once, at the end of the Servlet’s life cycle. The destroy() method lets your Servlet close database connections, stop background threads, write Cookie lists or click counters to disk, and perform other similar cleanup activities.

What is a Servlet container?

A Servlet container is a Web server that supports the Servlet protocol and listens on ports to receive requests. The received message is converted into a ServletRequest object and passed to the Servlet object. After the Servlet object processes the logic, the returned ServletResponse object is assembled into a response message and returned to the client.

Are servlets thread-safe?

The Servlet architecture is based on the Java multithreading mechanism, and its life cycle is the responsibility of the Web container. When the client first requests, the container instantiates the corresponding Servlet from web.xml, and subsequent requesting threads come in and do not instantiate the new Servlet object, meaning that multiple threads are using the Servlet object. Thus, when two or more threads access the same Servlet at the same time, it is possible for multiple threads to access the same resource at the same time, and the data may become inconsistent. Therefore, if you do not pay attention to thread safety when building Web applications with servlets, it will make the Servlet program difficult to find errors. So how do you write thread-safe servlets? There are three main ways:

  1. Implement the SingleThreadModel interface. This interface specifies how the system handles calls to the same Servlet. If a Servlet is specified by this interface, the service method in the Servlet will not be executed by two threads at the same time, and of course there will be no thread-safety issues. This method simply changes the previous definition of the HelloServlet class to:public class HelloServlet extends HttpServlet implements SingleThreadModel. This approach is not recommended after Servlet 2.4, because it causes Servlet objects to be created on every request, sacrificing space for safety, and incurs significant system overhead.
  2. usesynchronizedKeyword Manual synchronization
  3. Avoid instance variables. Thread-safety problems are caused by multiple threads reading and writing shared data simultaneously. So using local variables instead of instance variables in the service() method is the most convenient and least expensive.

Refer to the article

  • www.zhihu.com/question/21…
  • www.runoob.com/servlet/ser…
  • www.liaoxuefeng.com/wiki/125259…

This article code repository: github.com/JiangYongKa…