53. Servlet details and lifecycle hooks#
In this post, some details of servlet configuration are discussed, as well as techniques that you can use to hook into life cycle events, the main ones being application startup and -shutdown, and first request on a servlet.
53.1. Servlet configuration#
The @WebServlet
annotation offers several possibilities for configuration. Here are the interesting ones:
Name |
Type |
Required |
Description |
---|---|---|---|
urlPatterns or value |
String[] |
y |
Specify one or more URL patterns of the servlet. Either of attribute can be used, but not both |
asyncSupported |
String |
n |
Specify whether the servlet supports asynchronous operation mode. Default is false. |
initParams |
WebInitParam[] |
n |
Specify one or more initialization parameters of the servlet. Each parameter is specified by @WebInitParam annotation type. |
loadOnStartup |
int |
n |
Specify load-on-startup order of the servlet. Default is -1 |
53.1.1. @Webservlet - urlPatterns#
The urlPatterns
parameter specifies which urls will map on your servlet.
This configuration:
@WebServlet(name = "WelcomeServlet",
urlPatterns = {"/welcome", "/index", "/home"})
public class WelcomeServlet extends HttpServlet { ... }
maps all these requests to WelcomeServlet
:
53.1.2. @Webservlet - loadOnStartup#
The loadOnStartup
parameter is an integer which specifies the servlet load order.
The container loads servlets with lower values before servlets with higher values.
If loadOnStartup
is negative (it defaults to -1), the servlet will be loaded when the container decides to - typically on first access.
@WebServlet(urlPatterns = {"/welcome"},
loadOnStartup = 1)
//guarantees first loading at deployment
public class WelcomeServlet extends HttpServlet { ... }
53.1.3. @Webservlet – initParams#
Servlet initialization parameters are defined as instances of @WebInitParam
.
@WebServlet(urlPatterns = {"/welcome"},
initParams = {
@WebInitParam(name = "tempDir", value = "/tmp"),
@WebInitParam(name = "allowedFileTypes", value = "jpg,png")
})
public class WelcomeServlet extends HttpServlet {
@Override
public void init() throws ServletException {
final String tempDir = getInitParameter("tempDir");
System.out.println("tempDir = " + tempDir);
System.out.println("admin_email = " + getServletContext().getInitParameter("admin_email"));
}
//more code
}
will output to the console
tempDir = /tmp admin_email = admin\@example.com
You can specify the same information in web.xml, which seems a bit more logical:
<servlet-mapping>
<servlet-name>WelcomeServlet</servlet-name>
<url-pattern>/welcome</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>WelcomeServlet</servlet-name>
<servlet-class>nl.bioinf.wis_on_thymeleaf.servlets.WelcomeServlet</servlet-class>
<init-param>
<param-name>tempDir</param-name>
<param-value>/some/location</param-value>
</init-param>
</servlet>
53.1.4. @Webservlet versus web.xml configuration#
When configuration is done in both web.xml
ánd in @WebServlet
annotations, the web.xml
configuration takes precedence.
A use case for this behaviour would be: development mode versus production mode.
With these two “conflicting” configurations, the url will become /extra
and tempDir /some/location
. The url /welcome
will return a 404 not found!
@WebServlet(name = "WelcomeServlet",
urlPatterns = {"/welcome", "/home"},
initParams = {@WebInitParam(name = "tempDir", value = "/tmp")}
public class WelcomeServlet extends HttpServlet { }
<servlet-mapping>
<servlet-name>WelcomeServlet</servlet-name>
<url-pattern>/extra</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>WelcomeServlet</servlet-name>
<servlet-class>nl.bioinf.wis_on_thymeleaf.servlets.WelcomeServlet</servlet-class>
<init-param>
<param-name>tempDir</param-name>
<param-value>/some/location</param-value>
</init-param>
</servlet>
53.1.5. @Webservlet – asyncSupported#
This allows the servlet to store incoming requests for later response. For practical purposes, with this configuration you can set up a servlet that will (in effect) push data to the client (after the client sends the initial request to the server). This is very interesting, but outside the scope of this course.
53.2. Hooks#
Hooks are pieces of code that let you write code that will run at application life cycle events. The ones we will look at here are:
Application startup/shutdown hook
Servlet initialization/cleanup hooks
53.2.1. Application startup & shutdown#
If you want to do something at
startup – e.g. create a single template engine to service all servlets
shutdown – e.g. free DB resources you annotate a class with
@WebListener
and have it implement theServletContextListener
interface.
Here is an implementation. It uses the startup hook to create a single TemplateEngine
instance that can be served to all servlets, guaranteeing that this code will have run first and only once.
package nl.bioinf.wis_on_thymeleaf.config;
//imports removed
@WebListener
public class WebConfig implements ServletContextListener {
private static TemplateEngine templateEngine;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("[WebConfig] Initializing template engine");
createTemplateEngine(servletContextEvent.getServletContext());
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("Shutting down!");
}
private static void createTemplateEngine(ServletContext servletContext) {
ServletContextTemplateResolver templateResolver =
new ServletContextTemplateResolver(servletContext);
templateResolver.setTemplateMode("XHTML");
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCacheTTLMs(3600000L);
// Cache is set to true by default.
// Set to false if you want templates to be automatically
// updated when modified.
templateResolver.setCacheable(true);
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
WebConfig.templateEngine = templateEngine;
}
/**
* serves the template engine that was created at application startup.
* @return
*/
public static TemplateEngine getTemplateEngine() {
return templateEngine;
}
//method omitted
}
53.2.2. Servlet initialization and destroy#
When a first request is received for a servlet after application startup, the servlet container (Tomcat) will call
the init()
methods, if present. Method init()
is guaranteed to be called before the first call to service()
.
init(ServletConfig config)
is called by the servlet container to indicate to a servlet that the servlet is being placed into service.init()
is a convenience method which can be overridden so that there’s no need to call super.init(config).destroy()
is called by the servlet container to indicate to a servlet that the servlet is being taken out of service
There are two overloaded variants defined in class GenericServlet
that you can hook into to handle your startup actions:
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
As you can see the first one calls the second one. Depending on your need for the ServletConfig
object -which gives access to application-scoped variables-, you can choose either one of them to override. Here are all three (in class PhraseServlet
, for demo purposes):
@Override
public void init() throws ServletException {
//no super.init() required
System.out.println("[PhraseServlet] Running no-arg init()");
this.templateEngine = WebConfig.getTemplateEngine();
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config); //required in this implementation
System.out.println("[PhraseServlet] Running init(ServletConfig config)");
config.getServletContext().getInitParameter("admin_email");
}
@Override
public void destroy() {
super.destroy();
System.out.println("[PhraseServlet] Shutting down servlet service");
}
In general, you use these init() methods to initialize “expensive” resources that you only want to create once. Good examples are importing config files, creating database connections (although there may be better solutions for that) or getting template engines, as in this example. Likewise, the destroy
method can be used to elegantly shut down resources.