Servlet Init() method magic
January 20, 2012 Leave a comment
A Common Mistake in Servlet Init() Methods:
Servlet init
methods allows a servlet to perform one-time initialization prior to servicing requests. One common mistake when implementing init
method is in this form:
public void init(ServletConfig config) throws ServletException { //do custom initialization ... System.out.println(" init(ServletConfig config) invoked."); ... }
This is wrong because it doesn’t invoke super.init(ServletConfig)
. As a result, ServletConfig
is not stored in the servlet instance, and subsequent calls to getServletConfig will return null.
Another variant of this mistake is to store the ServletConfig
parameter in a class variable of the concrete servlet class:
private ServletConfig config; public void init(ServletConfig config) throws ServletException { this.config = config; System.out.println(" init(ServletConfig config) invoked."); //do custom initialization ... ... }
This is also wrong because config
saved in the current servlet won’t be available to its superclass, usually GenericServlet
or HttpServlet
. When the default implementation of getServletConfig()
method looks for ServletConfig
in superclasses, it’s still null. The only way it can work is that you also override getServletConfig
method to look in the concrete servlet class, which is unusual and unnecessary.
This is the error from Glassfish/JavaEE SDK 5, when running a servlet with those incorrect init
methods:
java.lang.NullPointerException test.HelloWorldServlet.doGet(HelloWorldServlet.java:14) javax.servlet.http.HttpServlet.service(HttpServlet.java:707) javax.servlet.http.HttpServlet.service(HttpServlet.java:820) com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:73) com.sun.enterprise.web.VirtualServerPipeline.invoke(VirtualServerPipeline.java:120) org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:231)
To implement servlet init
methods correctly, you have several options:
- If you only need to save
ServletConfig
, do not override anyinit
methods in servlet class. It’s already implemented in servlet superclassGenericServlet
. - If you have custom initialization work to do, override the no-arg
init()
method, and forget aboutinit(ServletConfig)
. Is it ok to callgetServletConfig()
method inside the no-arginit()
method? Yes, an instance ofServletConfig
has already been saved by superclassGenericServlet
. - If you really want to override
init(ServletConfig)
, make sure you invokesuper.init(ServletConfig);
, usually as the first line, though it’s not strictly required.
Why Servlet Init() Method confusing?
You may ask, what is the difference between servlet init()
and init(ServletConfig)
, and why is it so confusing?
When servlet was invented, there was only one init
method, the one with parameter ServletConfig
. The no-arg init
method was added around Servlet 2.3 timeframe, mainly to address this common mistake. This solution applies a Template Design Pattern to outline what needs to be done in init
method and also keeps it extensible for concrete servlet classes.
init(ServletConfig)
is the template method, which stores ServletConfig
, and then delegates to init()
. This is what javax.servlet.GenericServlet.init(ServletConfig)
looks like:
public void init(ServletConfig config) throws ServletException { this.config. = config; init(); }
The real work of initialization is supposed to be done in init()
method, which can be overrid by servlet subclasses. Its default implementation in javax.servlet.GenericServlet
is merely a no-op.
From the above code snippet, when init()
in your servlet class is invoked by the container, an instance of ServletConfig
has already been saved. So you can safely call getServletConfig()
inside of init()
method.
Servlet classes rarely need to know about init(ServletConfig )
method. Only web containers need to invoke it. Ideally, this method should be declared as final
or even private
in GenericServlet
. But that would break backward compatibility.
Having two overloaded init
methods may also add to the confusion. Unless developers read the Javadoc carefully, their relationship (one calling the other) is unclear. So it’s possible someone will override init()
method like this:
@Override public void init() throws ServletException { //do some initialization work first, //then call init(ServletConfig) init(null); }
It will cause infinite loop and java.lang.StackOverflowError
during servlet initialization, and the servlet will never be put into service. I hope I didn’t make it more confusing.
Recent Comments