Can we write an argument constructor in a Servlet? If yes, how can you call?
The problem can be state more generically:
"According to the servlets (2.3) specification, the servlets are instantiated by the servlet engine by invoking the no-arg constructor. How can I initialize a servlet properly given that correct initialization depends on the central/global/unique/application configuration?"
Actually, you can use serlvets with constructor and/or initialize them as you like. However, it requires a little bit of plumbing.
Assuming you have a servlet with a constructor having arguments:
package org.gawi.example.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SampleServlet extends HttpServlet
{
private final String mMessage;
public SampleServlet(String message)
{
mMessage = message;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/plain");
response.getWriter().write(mMessage);
}
}
The first thing you need is a unique servlet whithin your application, let's call it InitializationServlet, to create all the required instances. Those instances must then be exported in the servlet context to be retrieve by another servlet (explained later). The InitializationServlet may look like this:
package org.gawi.example.servlets;
import javax.servlet.*;
import javax.servlet.http.*;
public class InitializationServlet extends HttpServlet
{
public void init() throws ServletException
{
SampleServlet servletA = new SampleServlet("this is servlet A");
SampleServlet servletB = new SampleServlet("this is servlet B");
SampleServlet servletC = new SampleServlet("this is servlet C");
getServletContext().setAttribute("servletA", servletA);
getServletContext().setAttribute("servletB", servletB);
getServletContext().setAttribute("servletC", servletC);
}
}
You see that only the init()
method has been provided. This servlet is not servicing any HTTP request. Its only purpose is to store the servlet in the ServletContext. Note that you could have also use this servlet to load your application configuration. So this can act as the web-application entry point, like the main(String[] args)
method of a program. This might remind you of the ContextLoaderServlet of SpringSource.
The last piece is the DelegateServlet that will effectively be instantiated by the servlet container, only this servlet will forward all the pertinent method calls to the wrapped servlet instance:
package org.gawi.example.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DelegateHttpServlet extends HttpServlet
{
private static final String SERVLET_CONTEXT_KEY_INIT_PARAMETER = "servletContextKey";
private HttpServlet mServlet;
public void init(ServletConfig servletConfig) throws ServletException
{
super.init(servletConfig);
locateServlet(servletConfig);
mServlet.init(servletConfig);
}
private void locateServlet(ServletConfig servletConfig) throws ServletException
{
String servletContextAttributeName = servletConfig.getInitParameter(SERVLET_CONTEXT_KEY_INIT_PARAMETER);
if (servletContextAttributeName == null)
{
throw new ServletException("Unable to find init parameter '" + SERVLET_CONTEXT_KEY_INIT_PARAMETER + "'");
}
Object object = servletConfig.getServletContext().getAttribute(servletContextAttributeName);
if (object == null)
{
throw new ServletException("Unable to find " + servletContextAttributeName + " in servlet context.");
}
if (!(object instanceof HttpServlet))
{
throw new ServletException("Object is not an instance of"
+ HttpServlet.class.getName()
+ ". Class is "
+ object.getClass().getName()
+ ".");
}
mServlet = (HttpServlet) object;
}
public void destroy()
{
mServlet.destroy();
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
{
mServlet.service(req, res);
}
}
During its initialization, the DelegateServlet will look-up the target servlet in the servlet context using the servletContextKey
servlet initial argument.
The web.xml for such an application might look like that:
Example
Example web showing handling of servlets w/ constructors.
Initialization
org.gawi.example.servlets.InitializationServlet
1
A
org.gawi.example.servlets.DelegateHttpServlet
servletContextKey
servletA
2
B
org.gawi.example.servlets.DelegateHttpServlet
servletContextKey
servletB
3
C
org.gawi.example.servlets.DelegateHttpServlet
servletContextKey
servletC
4
A
/servlet/a
B
/servlet/b
C
/servlet/c
5
Be sure to load the InitializationServlet first, using a low
value.
The benefit of this approach is that HttpServlet
objects can be handled like any other regular Java object or bean. Hence, it provides a better control over initialization: no more tricky stuff to do in the init()
method, nor messy servlet init-arg handling.