Servlet Init() method magic

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 any init methods in servlet class. It’s already implemented in servlet superclass GenericServlet.
  • If you have custom initialization work to do, override the no-arg init() method, and forget about init(ServletConfig). Is it ok to call getServletConfig() method inside the no-arg init() method? Yes, an instance of ServletConfig has already been saved by superclass GenericServlet.
  • If you really want to override init(ServletConfig), make sure you invoke super.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.

Difference between servletContext and ServletConfig

ServletConfig
ServletConfig is implemented by the servlet container to initialize a single servlet using init().  you can pass initialization parameters to the servlet using the web.xml deployment descriptor. Every servlet has its own ServletConfig object.

Example code:

<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>com.shivasoft.ServletConfigTest</servlet-class>
<init-param>
<param-name>article</param-name>
<param-value>Difference between servletContext and ServletConfig</param-value>
</init-param>
</servlet>

ServletContext
ServletContext is implemented by the servlet container for all servlet to communicate with its servlet container. It is applicable only within a single Java Virtual Machine.
The ServletContext object is contained within the ServletConfig object. That is, the ServletContext can be accessed using the ServletConfig object within a servlet. You can specify param-value pairs for ServletContext object in  <context-param> tags in web.xml file. ServletContext is created at the application level and shared by all the Servlet codes.

Example : Database string used by the application.

<context-param>
<param-name>dbString</param-name>
<param-value>Provider=MySQLProv;Data Source=shivasoft;User Id=shiva; Password=soft;</param-value>
</context-param>

difference in ServletRequest.getRequestDispather() and ServletContext.getRequestDispatcher() in Servlet

Servletrequest.getRequestDispatcher(“url”) means the dispatch is relative to the current HTTP request.
Example code:

RequestDispatcher reqDispObj = request.getRequestDispatcher("/login.jsp");

getServletContext().getRequestDispatcher(“url”) means the dispatch is relative to the root of the ServletContext.
Example code:

RequestDispatcher reqDispObj = getServletContext().getRequestDispatcher("/testApp/login.jsp");

Why not to write constructor in Servlet

Technically you can define constructors in servlet. But, the declared constructor cannot access the ServletConfig object or throw a ServletException.

Then why is it not customary to declare a constructor in a servlet? Because the init() method is used to perform servlet initialization. In JDK 1.0 (servlet were written in this version), constructors for dynamically loaded Java classes such as servlets cannot accept arguments. Therefore init() was used to initialize by passing the implemented object of ServletConfig interface and other needed parameters.
Also, Java constructors cannot be declared in interfaces. So, javax.servlet.Servlet interface cannot have a constructor that accepts a ServletConfig parameter. To overcome this, init() method is used for initialization instead of declaring a constructor.

What is preinitialization of servlet

In the java servlet life cycle, the first phase is called “Creation and intialization“.

The java servlet container first creates the servlet instance and then executes the init() method. This initialization can be done in Two ways. The default way is that, the java servlet is initialized when the servlet is called for the first time. This type of servlet initialization is called lazy loading.

The other way is through the <load-on-startup>non-zero-integer</load-on-startup> tag using the deployment descriptor web.xml. This makes the java servlet to be loaded and initialized when the server starts. This process of loading a java servlet before receiving any request is called preloading or preinitialization of a servlet.
Servlet are loaded in the order of number(non-zero-integer) specified. That is, lower(example: 1) the load-on-startup value is loaded first and then servlet with higher values are loaded.

<pre><servlet>
       <servlet-name>Servlet-URL</servlet-name>
       <servlet-class>com.shivasoft.LoginServlet</servlet-class>
       <load-on-startup>2</load-on-startup>
</servlet></pre>

Example to Override the init() method of the servlet

It is not recommended to override the init() method of the servlet.

Here is an example to override init() method of servlet:

public class BookDBServlet ... {

    private BookstoreDB books;

    public void init(ServletConfig config) throws ServletException {

        // Store the ServletConfig object and log the initialization
        super.init(config);

        // Load the database to prepare for requests
        books = new BookstoreDB();
    }
    ...
}

you must write super.init(config) code and after that program specific logic.

How container handles the Servlet request

1. User clicks a link that has a URL of Servlet.

2. Container (Apache Tomcat is one of the example) sees that the request is for servlet , so create two objects :

HttpServletRequest
HttpServletResponse

3. Container finds correct servlet on the basis of URL passed with the help deployment descriptor (web.xml) file. Creates / Allocate thread for that request and pass request and response object to servle thread.

4. Container calls the servlets service() method, on the type of request, service calls doGet() or doPost() methods.

5. Lets assume that service calls the doPost() method. doPost() method generates dynamic page and add the page in response object.

6. Thread completes, container converts the response object into HttpResponse object and destroys the response and request object.