The servlet is an important part of the Java EE Specification system and the basic skills that Java developers must have, this article mainly introduces some important new features introduced by Servlet 3.0, including asynchronous processing, new annotation support, pluggable support, etc. Clear the obstacles for readers to smooth the transition to the new version.
0: Servlet 3.0 features Overview
1) Asynchronous processing support: With this feature, the servlet thread no longer needs to block until the business has finished processing before it can output a response, and finally ends the servlet thread. After a request is received, the Servlet thread can delegate the time-consuming operation to another thread to complete itself and return to the container without generating a response. This will significantly reduce server resource usage and increase concurrent processing speed for more time-consuming business processes.
2) Added annotation support: This version adds several annotations to simplify the declaration of the Servlet, filter, and Listener (Listener), which makes the Web. XML deployment profile no longer required from that version.
3) Pluggable support: Developers who are familiar with STRUTS2 will be sure to remember their integration with the various common frameworks, including Spring, through plug-ins. The plug-in is encapsulated into a JAR package and placed under the classpath, which can be loaded automatically by the STRUTS2 runtime. Now Servlet 3.0 provides a similar feature that allows developers to easily extend the functionality of existing WEB applications in a plug-in way without having to modify their existing applications.
Below we will explain the new features, and through the following learning, readers will be able to clearly understand the changes in Servlet 3.0, and the smooth use of it for daily development work.
One: Asynchronous processing support
Before
Servlet 3.0, the main workflow for a common servlet was roughly the following: first, after the servlet receives the request, it may need to preprocess the data that the request carries, and then invoke some methods of the business interface to complete the business process; The Servlet thread ends by submitting a response based on the result of the processing. The second step of the business process is usually the most time-consuming, mainly in the database operations, as well as other cross-network calls, and so on, in this process, the Servlet thread has been in a blocking state until the business method execution is complete. In the process of dealing with the business, the Servlet resources are always occupied and not released, which can cause performance bottlenecks for large, concurrent applications. In this respect, a private solution was used previously to end the Servlet thread prematurely and release resources in a timely manner.
Servlet 3.0 has done pioneering work on this issue, and now by using the asynchronous processing support of Servlet 3.0, the previous servlet processing process can be tuned to the following process: First, the servlet receives the request, It is possible to pre-preprocess the requested data first, and then the servlet thread forwards the request to an asynchronous thread to perform the business processing, and the thread itself returns to the container, where the servlet has not generated the response data, and after the asynchronous thread has finished processing the business, The response data can be generated directly (the asynchronous thread has a reference to the ServletRequest and Servletresponse objects), or the request continues to be forwarded to the other Servlet. As a result, the Servlet thread is no longer stuck in a blocking state waiting for the processing of the business logic, but instead starts the asynchronous thread and can return immediately. The
Asynchronous processing attribute can be applied to both servlet and filter components, because the asynchronous processing of the working mode and the normal mode of operation are fundamentally different, so by default, servlets and filters do not turn on the asynchronous processing feature, if you want to use the attribute, It must be enabled as follows:
for configuring Servlets and filters using the traditional deployment profile (Web. xml), Servlet 3.0 adds a sub-label for the and label, and the default value of the label is false, to enable asynchronous processing support, set it to Tru E can. In the case of a Servlet, it is configured as follows:
<servlet> <servlet-name>DemoServlet</servlet-name> <servlet-class>footmark.servlet.Demo Servlet</servlet-class> <async-supported>true</async-supported> </servlet>
For a servlet or filter configuration using the @WebServlet and @WebFilter provided by Servlet 3.0, both annotations provide the Asyncsupported property, which evaluates to False by default, to enable asynchronous processing support, only You need to set this property to True. Take @WebFilter as an example, configured as follows:
@WebFilter(urlPatterns = "/demo",asyncSupported = true) public class DemoFilter implements Filter{...}
A simple example of a Servlet that simulates asynchronous processing is as follows:
@WebServlet(urlPatterns = "/demo", asyncSupported = true)public class AsyncDemoServlet extends HttpServlet { @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {resp.setContentType("text/html;charset=UTF-8");PrintWriter out = resp.getWriter();out.println("进入Servlet的时间:" + new Date() + ".");out.flush();//在子线程中执行业务调用,并由其负责输出响应,主线程退出AsyncContext ctx = req.startAsync();new Thread(new Executor(ctx)).start();out.println("结束Servlet的时间:" + new Date() + ".");out.flush(); }}public class Executor implements Runnable { private AsyncContext ctx = null; public Executor(AsyncContext ctx){this.ctx = ctx; } public void run(){try { //等待十秒钟,以模拟业务方法的执行 Thread.sleep(10000); PrintWriter out = ctx.getResponse().getWriter(); out.println("业务处理完毕的时间:" + new Date() + "."); out.flush(); ctx.complete();} catch (Exception e) { e.printStackTrace();} }}
In addition, Servlet 3.0 provides a listener for asynchronous processing, expressed using the Asynclistener interface. It can monitor the following four types of events:
When the asynchronous thread starts, call the Asynclistener Onstartasync (AsyncEvent event) method;
When an asynchronous thread is faulted, call the Asynclistener OnError (AsyncEvent event) method;
Asynchronous thread execution timed out, call Asynclistener's OnTimeOut (AsyncEvent event) method;
When the asynchronous execution is complete, call the Asynclistener OnComplete (AsyncEvent event) method;
To register a asynclistener, simply pass the prepared Asynclistener object to the AddListener () method of the Asynccontext object, as follows:
AsyncContext ctx = req.startAsync(); ctx.addListener(new AsyncListener() { public void onComplete(AsyncEvent asyncEvent) throws IOException { // 做一些清理工作或者其他 } ... });
Second: Added annotation support
The deployment profile for Servlet 3.0 The top-level label for Web. XML has a Metadata-complete property that specifies whether the current deployment profile is complete. If set to true, the container will only rely on the deployment profile at deployment time, ignoring all annotations (also skipping web-fragment.xml scans, i.e. disabling pluggable support, see the following for pluggable support); If you do not configure this property, or set it to False, annotation support (and pluggable support) is enabled.
@WebServlet is used to declare a class as a servlet, which will be handled by the container at deployment time, and the container will deploy the appropriate class as a servlet based on the specific property configuration. The note has some of the common properties given in the following table (all of which are optional), but Vlaue or urlpatterns are usually required and cannot coexist, and if specified at the same time, the value of value is usually ignored:
The following is a simple example:
@WebServlet(urlPatterns = {"/simple"}, asyncSupported = true, loadOnStartup = -1, name = "SimpleServlet", displayName = "ss", initParams = {@WebInitParam(name = "username", value = "tom")}) public class SimpleServlet extends HttpServlet{ … }
With this configuration, you do not have to configure the corresponding and elements in Web. XML, and the container publishes the class as a Servlet at deployment time, based on the specified properties. Its equivalent web. XML configuration form is as follows:
<servlet> <display-name>ss</display-name> <servlet-name>SimpleServlet</servlet-name> <servlet-class>footmark.servlet.SimpleServlet</servlet-class> <load-on-startup>-1</load-on-startup> <async-supported>true</async-supported> <init-param><param-name>username</param-name><param-value>tom</param-value> </init-param></servlet><servlet-mapping> <servlet-name>SimpleServlet</servlet-name> <url-pattern>/simple</url-pattern></servlet-mapping>
@WebInitParam
This annotation is usually not used alone, but is used in conjunction with @WebServlet or @WebFilter. Its purpose is to specify the initialization parameters for the Servlet or filter, which is equivalent to the child tags in Web. Xml.
@WebFilter is used to declare a class as a filter that will be handled by the container at deployment time, and the container will deploy the appropriate class as a filter based on the specific property configuration. The note has some of the common properties given in the following table (all the properties below are optional, but value, Urlpatterns, Servletnames must contain at least one, and value and urlpatterns cannot coexist, and if specified at the same time, it is generally ignored Value):
The following is a simple example:
@WebFilter(servletNames = {"SimpleServlet"},filterName="SimpleFilter") public class LessThanSixFilter implements Filter{...}
With this configuration, you do not have to configure the corresponding and elements in Web. XML, and the container publishes the class as a filter at deployment time, based on the specified properties. Its equivalent in Web. XML is configured in the following form:
<filter> <filter-name>SimpleFilter</filter-name> <filter-class>xxx</filter-class> </filter> <filter-mapping> <filter-name>SimpleFilter</filter-name> <servlet-name>SimpleServlet</servlet-name> </filter-mapping>
@WebListener
This annotation is used to declare a class as a listener, and the class that is @WebListener labeled must implement at least one of the following interfaces:
ServletContextListener ServletContextAttributeListener ServletRequestListener ServletRequestAttributeListener HttpSessionListener HttpSessionAttributeListener
A simple example is as follows:
@WebListener("This is only a demo listener") public class SimpleListener implements ServletContextListener{...}
If so, you do not need to configure the tags in Web. Xml. It is equivalent to the configuration form in Web. Xml as follows:
<listener> <listener-class>footmark.servlet.SimpleListener</listener-class> </listener>
@MultipartConfig
This note is primarily intended to assist in the support provided by HttpServletRequest in Servlet 3.0 for uploading files. The note is labeled above the servlet to indicate that the MIME type of the request that the servlet wishes to process is multipart/form-data.
Three: Pluggable support
If the new annotation support for version 3.0 is to simplify the declaration of the servlet/filter/listener, so that Web. XML becomes an optional configuration, the new pluggable (pluggability) support increases the flexibility of the Servlet configuration to the next level. Developers familiar with Struts2 know that STRUTS2 provides support for various development frameworks, including Spring, in the form of plug-ins, and developers can even develop plug-ins for Struts2 themselves, and the Servlet's pluggable support is based on this idea. With this feature, we can now extend the new functionality without modifying the existing WEB application, simply by placing the JAR package in a certain format into the Web-inf/lib directory, with no additional configuration required.
Servlet 3.0 introduces a Web-fragment.xml deployment profile called a "Web module deployment Descriptor Fragment" that must be stored in the Meta-inf directory of the JAR file, which can contain everything that can be defined in XML. The content. The JAR package is usually placed in the Web-inf/lib directory, except that all the resources used by the module, including class files, configuration files, etc., only need to be able to be loaded by the container ClassLoader chain, such as the classes directory.
Now, there are three ways to add a servlet configuration to a Web app (filters, listeners, and servlets are all equivalent, so here's a servlet configuration example, with filters and listeners with very similar features):
1. Write A class inherits from HttpServlet, puts the class in the corresponding package structure under the classes directory, modifies Web. XML, and adds a Servlet declaration to it. This is the most primitive way;
2. Write a class that inherits from HttpServlet and uses @WebServlet annotations on that class to declare the class as a Servlet, placing the class in the corresponding package structure in the classes directory without modifying the Web. xml file.
3. Write a class that inherits from HttpServlet, puts the class into a jar package, and places a Web-fragment.xml file under the Meta-inf directory of the Jar package, which declares the corresponding Servlet configuration. An example of the Web-fragment.xml file is as follows:
<?xml version="1.0" encoding="UTF-8"?><web-fragment xmlns=http://java.sun.com/xml/ns/javaee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd" metadata-complete="true"> <servlet><servlet-name>fragment</servlet-name><servlet-class>footmark.servlet.FragmentServlet</servlet-class> </servlet> <servlet-mapping><servlet-name>fragment</servlet-name><url-pattern>/fragment</url-pattern> </servlet-mapping></web-fragment>
As can be seen from the above example, the principal configuration of Web-fragment.xml and Web. XML is exactly the same as the Web. XML except that the XSD reference to the header declaration is different.
Because multiple Web-fragment.xml declaration files can appear in a WEB application, plus an XML file, the load order issue becomes a problem that has to be faced. The Servlet specification's expert group has taken this into account at design time and defined the rules for loading order.
Web-fragment.xml contains two optional top-level labels, and if you want to specify an explicit load order for the current file, you typically need to use these two tags, which are used primarily to identify the current file, and to specify the order of precedence. A simple example is as follows:
<web-fragment...> <name>FragmentA</name> <ordering><after> <name>FragmentB</name> <name>FragmentC</name></after> <before><others/> </before> </ordering> ...</web-fragment>
As shown above, the value of the tag is usually referenced by other web-fragment.xml files in the defined order, which is generally not needed in the current file, and it plays a role in identifying the current file.
Inside the tag, we can define the relative position of the current Web-fragment.xml file with other files, which is implemented mainly through the and sub-tags. Within these two sub-tags, you can specify the corresponding file by tag. Like what:
<after> <name>FragmentB</name> <name>FragmentC</name> </after>
The above fragment indicates that the current file must be parsed after FRAGMENTB and FRAGMENTC. is used in this same way, it means that the current file must be earlier than the Web-fragment.xml file listed in the label.
In addition to comparing the files that are listed in and, the Servlet provides a simplified label. It represents all other web-fragment.xml files except the current file. The label has a lower priority than the use of a clearly specified relative position relationship.
Four: ServletContext Performance enhancements
In addition to the new features above, the functionality of the ServletContext object has been enhanced in the new version. The object now supports dynamically deploying Servlets, filters, listeners at run time, as well as adding URL mappings for servlets and filters. In the case of Servlets, the filter is similar to the listener. ServletContext adds the following methods for dynamically configuring Servlets:
ServletRegistration.Dynamic addServlet(String servletName,Class<? extends Servlet> servletClass)ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)ServletRegistration.Dynamic addServlet(String servletName, String className)<T extends Servlet> T createServlet(Class<T> clazz)ServletRegistration getServletRegistration(String servletName)Map<String,? extends ServletRegistration> getServletRegistrations()
The first three methods are the same, only the parameter types are different; Servlets created with the Createservlet () method typically require some custom configuration and then use the Addservlet () method to dynamically register it as a service-ready Servlet. The two getservletregistration () methods are primarily used to dynamically add mapping information to the servlet, which is equivalent to adding mapping information to the servlet in Web. XML (or Web-fragment.xml) using a label for the presence.
The above ServletContext new method is either called in the Servletcontextlistener contexinitialized method, or in the Servletcontainerinitializer Called in the Onstartup () method.
Servletcontainerinitializer is also a new interface for Servlet 3.0, which uses the Jar service API (Jar Services API) at startup to discover Servletcontainerinitializer's real Now class, and the container web-inf/lib the classes in the JAR package to the Onstartup () method of the class, we usually need to use @HandlesTypes annotations on the implementation class to specify the class that you want to process, filtering out the unwanted onstartup () The class to process.
V: HttpServletRequest support for file uploads
Previously, the process of uploading files was always a headache for developers, because the Servlet itself did not provide direct support, needed to be implemented using a third-party framework, and was not easy to use. Now that's history, Servlet 3.0 has provided this functionality, and it's very simple to use. To do this, HttpServletRequest provides two methods to parse the uploaded file from the request:
Part getPart(String name)Collection<Part> getParts()
The former is used to get the file given name in the request, which is used to get all the files. Each file is represented by a Javax.servlet.http.Part object. This interface provides an easy way to process files, such as write (), delete (), and so on. At this point, combining httpservletrequest and part to save the uploaded file becomes very simple, as follows:
Part photo = request.getPart("photo"); photo.write("/tmp/photo.jpg"); // 可以将两行代码简化为 request.getPart("photo").write("/tmp/photo.jpg") 一行。
In addition, developers can work with the aforementioned @MultipartConfig annotations to make some customizations to the upload operation, such as restricting the size of the uploaded file, and saving the path of the file. The usage is very simple, so we don't repeat it here.
It is important to note that if the requested MIME type is not multipart/form-data, you cannot use the two methods above, or you will throw an exception.
Servlet 3.0 Features Detailed