1. Introduction to Servlet
Servlet is a technology provided by Sun Company for developing dynamic web resources.
Sun provides a servlet interface in its API. If users want to send a dynamic web resource (that is, develop a Java program to output data to the browser), they need to complete the following two steps:
1. Write a Java class to implement the servlet interface.
2. Deploy the developed Java classes to the web server.
According to a conventional name habit, we usually call Java programs that implement the servlet interface Servlet.
2. The operation process of servlet
The Servlet program is called by the WEB server. After the web server receives the client's Servlet access request:
①The web server first checks whether it has been loaded and created an instance object of the Servlet. If so, then execute step 4 directly; otherwise, execute step 2.
② Load and create an instance object of the Servlet.
③Call the init() method of the Servlet instance object.
④ Create an HttpServletRequest object for encapsulating HTTP request messages and an HttpServletResponse object representing HTTP response messages, and then call the Servlet's service() method and pass the request and response objects as parameters.
⑤ Before the WEB application is stopped or restarted, the Servlet engine will uninstall the Servlet and call the destroy() method of the Servlet before uninstalling.
3. Servlet call diagram
4. Develop Servlet in Eclipse
Create a new web project in eclipse, and eclipse will automatically create the directory structure shown in the figure below:
4.1. Servlet interface implementation class
Servlet interface SUN company defines two default implementation classes, namely: GenericServlet and HttpServlet.
HttpServlet refers to a servlet that can handle HTTP requests. It adds some HTTP protocol processing methods to the original servlet interface, which is more powerful than the servlet interface. Therefore, when writing Servlets, developers should usually inherit this class and avoid directly implementing the Servlet interface.
When HttpServlet implements the Servlet interface, it overwrites the service method. The code in the method body will automatically determine the user's request method. If it is a GET request, the doGet method of HttpServlet is called. If it is a Post request, the doPost method will be called. Therefore, when writing Servlets, developers usually only need to overwrite the doGet or doPost method instead of overwriting the service method.
4.2. Create and write Servlets through Eclipse
Select the gacl.servlet.study package, right-click → New → Servlet, as shown in the figure below:
In this way, we will use Eclipse to help us create a Servlet with the name ServletDemo1. There will be the following code in the created ServletDemo01:
package gacl.servlet.study;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletDemo1 extends HttpServlet { /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML PUBLIC /"-//W3C//DTD HTML 4.01 Transitional//EN/">"); out.println("<HEAD><TITLE>A Servlet</TITLE></HEAD>"); out.println(" <BODY>"); out.print(" This is "); out.print(this.getClass()); out.println(", using the GET method"); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML PUBLIC /"-//W3C//DTD HTML 4.01 Transitional//EN/">"); out.println("<HTML>"); out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); out.println(" <BODY>"); out.println(" <BODY>"); out.println("This is "); out.print(this.getClass()); out.println(", using the POST method"); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); }}These codes are automatically generated by Eclipse, and there are two pairs of tags in the web.xml file, <servlet></servlet> and <servlet-mapping></servlet-mapping>. These two pairs of tags are configured with ServletDemo1, as shown in the figure below:
Then we can access the ServletDemo1 Servlet through the browser, as shown in the figure below:
5. Pay attention to details in Servlet development
5.1. Servlet access URL mapping configuration
Since the client accesses resources in the web server through a URL address, if the servlet program wants to be accessed by the outside world, it must map the servlet program to a URL address. This work is done in the web.xml file using the <servlet> element and <servlet-mapping> element.
The <servlet> element is used to register a servlet. It contains two main child elements: <servlet-name> and <servlet-class>, which are used to set the registration name of the servlet and the full class name of the servlet respectively.
A <servlet-mapping> element is used to map an external access path to a registered Servlet. It contains two child elements: <servlet-name> and <url-pattern>, which are used to specify the registration name of the Servlet and the external access path of the Servlet. For example:
<servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/servlet/ServletDemo1</url-pattern> </servlet-mapping> The same Servlet can be mapped to multiple URLs, that is, the setting value of the <servlet-name> child element of multiple <servlet-mapping> elements can be the registration name of the same Servlet. For example: <servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/servlet/ServletDemo1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/1.htm</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/2.jsp</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/3.php</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/4.ASPX</url-pattern> </servlet-mapping>
Through the above configuration, when we want to access a Servlet with the name ServletDemo1, we can use the following addresses to access:
http://localhost:8080/JavaWeb_Servlet_Study_20140531/servlet/ServletDemo1
http://localhost:8080/JavaWeb_Servlet_Study_20140531/1.htm
http://localhost:8080/JavaWeb_Servlet_Study_20140531/2.jsp
http://localhost:8080/JavaWeb_Servlet_Study_20140531/3.php
http://localhost:8080/JavaWeb_Servlet_Study_20140531/4.ASPX
ServletDemo1 is mapped to multiple URLs.
5.2. Use * wildcard mapping for Servlet access URLs
The * wildcard character can also be used in the URLs to which the Servlet maps, but there can only be two fixed formats: one is the "*. extension", and the other is the starting with a forward slash (/) and ending with a "/*". For example:
<servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/*</url-pattern>
*It can match any character, so you can use any URL to access the ServletDemo1 Servlet, as shown in the figure below:
For some mapping relationships below:
Servlet1 maps to /abc/*
Servlet2 maps to /*
Servlet3 maps to /abc
Servlet4 maps to *.do
question:
When the request URL is "/abc/a.html", "/abc/*" and "/*" both match, which servlet responds to the Servlet engine will call Servlet1.
When the request URL is "/abc", both "/abc/*" and "/abc" match, which servlet responds to the Servlet engine will call Servlet3.
When the request URL is "/abc/a.do", both "/abc/*" and "*.do" match, which servlet responds to the Servlet engine will call Servlet1.
When the request URL is "/a.do", both "/*" and "*.do" match, which servlet responds to the Servlet engine will call Servlet2.
When the request URL is "/xxx/yyy/a.do", both "/*" and "*.do" match, which servlet responds to Servlet engine will call Servlet2.
The principle of matching is "whoever looks more like will find whoever looks more"
5.3. The difference between Servlet and ordinary Java classes
Servlet is a Java class for call by other Java programs (Servlet engines). It cannot run independently, and its operation is completely controlled and scheduled by the Servlet engine.
For multiple Servlet requests from the client, usually the server will only create a Servlet instance object. That is to say, once the Servlet instance object is created, it will reside in memory and serve other subsequent requests. The servlet instance object will not be destroyed until the web container exits.
During the entire life of a servlet, the servlet's init method is called only once. Each access request to a servlet causes the servlet engine to call the servlet service method once. For each access request, the Servlet engine will create a new HttpServletRequest request object and a new HttpServletResponse response object, and then pass these two objects as parameters to the service() method of the Servlet it calls. The service method then calls the doXXX method according to the request method.
If a <load-on-startup> element is configured in the <servlet> element, then when the WEB application starts, it will load and create the Servlet instance object and call the init() method of the Servlet instance object.
For example:
<servlet> <servlet-name>invoker</servlet-name> <servlet-class> org.apache.catalina.servlets.InvokerServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>
Purpose: Write an InitServlet for the web application. This servlet is configured to load on startup to create necessary database tables and data for the entire web application.
5.4. Default Servlet
If the mapping path of a servlet is only a forward slash (/), then this servlet becomes the default servlet of the current web application.
Any URL of the matching <servlet-mapping> element that cannot be found in the web.xml file, their access requests will be handed over to the default Servlet for processing, that is, the default Servlet is used to handle access requests that are not processed by other Servlets. For example:
<servlet> <servlet-name>ServletDemo2</servlet-name> <servlet-class>gacl.servlet.study.ServletDemo2</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- Configure ServletDemo2 as the default Servlet --> <servlet-mapping> <servlet-name>ServletDemo2</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
When accessing a non-existent servlet, the configured default servlet is used for processing, as shown in the figure below:
In the <tomcat installation directory>/conf/web.xml file, a servlet named org.apache.catalina.servlets.DefaultServlet is registered, and this servlet is set as the default servlet.
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- The mapping for the default servlet --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
When accessing a static HTML file and image in the Tomcat server, you are actually accessing this default servlet.
5.5. Servlet thread safety issues
When multiple clients access the same Servlet concurrently, the web server will create a thread for each client's access request and call the Servlet's service method on this thread. Therefore, if the same resource is accessed in the service method, it may cause thread safety problems. For example, the following code:
Code that does not have thread safety issues:
package gacl.servlet.study;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletDemo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * When multiple threads access the code in this method concurrently, will there be thread safety problems? The i variable is accessed concurrently by multiple threads, but there is no thread safety problem, because i is a local variable in the doGet method. * When multiple threads access the doGet method concurrently, each thread has its own i variable, * Each thread operates its own i variable, so there is no thread safety problem* When multi-threads access a certain method concurrently, if some resources (variables, collections, etc.) are defined inside the method * Then every thread has these things, so there is no thread safety problem*/ int i=1; i++; response.getWriter().write(i); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }} Code with thread safety issues:
package gacl.servlet.study;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletDemo3 extends HttpServlet { int i=1; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { i++; try { Thread.sleep(1000*4); } catch (InterruptedException e) { e.printStackTrace(); } response.getWriter().write(i+""); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}Define i as a global variable. When multiple threads access variable i concurrently, there will be thread safety problems, as shown in the figure below: Turn on two browsers at the same time to simulate concurrent access to the same Servlet. Normally, the first browser should see 2, and the second browser should see 3, but both browsers see 3, which is not normal.
Thread safety issues only exist when multiple threads operate the same resource concurrently. Therefore, when writing a servlet, if a certain resource (variable, collection, etc.) is accessed concurrently, there will be thread safety issues. So how to solve this problem?
Let's take a look at the following code:
package gacl.servlet.study;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletDemo3 extends HttpServlet { int i=1; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * After synchronized is added, there is no thread safety problem when concurrent access to i. * Why is there no thread safety problem after synchronized is added? * If there is a thread accessing the Servlet object now, it will first get the lock of the Servlet object* After it is executed, it will return the lock to the Servlet object. Since it first gets the lock of the Servlet object, * So when another thread accesses the Servlet object, since the lock has been taken away by the previous thread, the subsequent thread can only queue up * */ synchronized (this) {//In java, each object has a lock, and this here refers to the Servlet object i++; try { Thread.sleep(1000*4); } catch (InterruptedException e) { e.printStackTrace(); } response.getWriter().write(i+""); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}Now this approach is to add a lock to the Servlet object, ensuring that only one thread is accessing the resources in the Servlet object at any time, so there will be no thread safety issues, as shown in the figure below:
Although this approach solves thread safety problems, writing servlets must not handle thread safety problems in this way. If 9999 people access the servlet at the same time, then these 9999 people must queue up to access in sequence.
In response to the thread safety problem of servlets, Sun provides a solution: let the servlet implement a SingleThreadModel interface. If a servlet implements the SingleThreadModel interface, the Servlet engine will call its service method in single-thread mode.
Looking at the Sevlet API, you can see that the SingleThreadModel interface does not define any methods or constants. In Java, an interface that does not define any methods or constants is called a tag interface. One of the most typical tag interfaces that you often see is "Serializable". This interface also does not define any methods or constants. What is the use of tag interfaces in Java? The main function is to mark an object and tell the JVM what this object can do. For example, the object of the class that implements the "Serializable" interface can be serialized, and there is also a "Cloneable" interface, which is also a tag interface. By default, objects in Java are not allowed to be cloned, just like people in real life, cloning is not allowed, but as long as the "Cloneable" interface is implemented, the object can be cloned.
Let the Servlet implement the SingleThreadModel interface, just add the declaration to implement the SingleThreadModel interface to the definition of the Servlet class.
For servlets that implement the SingleThreadModel interface, the Servlet engine still supports multi-thread concurrent access to the servlet. The method is to generate multiple Servlet instance objects, and each concurrent thread calls an independent Servlet instance object separately.
Implementing the SingleThreadModel interface cannot really solve the thread safety problem of Servlets, because the Servlet engine will create multiple Servlet instance objects, and truly solving the multi-thread safety problem refers to the problem that a Servlet instance object is called by multiple threads at the same time. In fact, in Servlet API 2.4, SingleThreadModel has been marked as Deprecated (outdated).
The above is all about this article, I hope it will be helpful to everyone's learning.