04 April 2012

WebLogic and EJB 3.1 @Singleton @Startup with @PostConstruct


That's quite the mouthful of annotations ..

A question was posed recently on the WLS EJB OTN forum asking about why WLS doesn't correctly support this combination of annotations, where the method with the @PostConstruct annotation was not  being called as expected. 

I thought I'd check it out with a simple test, which I'm sharing here. 

1. Using NetBeans, I created a new "Web Application" project and assigned it to use my local WebLogic Server 12c installation. 



2.Within the project, I created an EJB 3.1 Singleton using the NetBeans wizard.  Not that creating EJBs in Java EE 6 requires this sort of assistance any more, having done away with most of the gunk from earlier versions of the specification.  With EJB 3.1, an EJB can now be just a class with annotations and the logic.  That's it. Simple.



3. On the EJB 3.1 Singleton, I then added the @Startup annotation to indicate that the bean must be instantiated when the container starts.  I also added a method which I annotated with @PostContruct to indicate it should be called after the class has been instantiated via its constructor.  The method prints a message to standard out when it is called.

I also added an instance variable with a default value, that is subsequently changed in the init method.  Accessing this from a servlet will also show whether the init method was invoked.
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sab.demo;

import java.util.Date;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.LocalBean;
import javax.ejb.Startup;

/**
 *
 * @author sbutton
 */
@Singleton
@Startup
public class TestSingletonBean {
    
    private String TESTVAL = "IF YOU SEE THIS @POSTCONSTRUCT HAS NOT BEEN CALLED";
    
    @PostConstruct
    void init() {
        TESTVAL = "@PostConstruct method was called on " + new Date();
        System.out.printf("\n\nIn init: %s\n", TESTVAL);
    }
    
    public String getTestVal() {
        return TESTVAL; 
    }    
}

5. Since this test app is making use of the new Java EE 6 ease-of-use features that support the deployment of EJBs in Web applications, I could simply deploy this web application to see if the EJB Singleton was started on deployment and whether the @PostConstruct method was called.


Looking on the console where WebLogic Server was started in NetBeans, the message from the init method is seen right after the application deployment completes.


This demonstrates that WebLogic Server is correctly handling EJB 3.1 with @Singleton, @Startup and @PostConstruct.
 
6. Taking it one minor step further.

To independently observe the value of TESTVAL to ensure it has been modified via the init method, in the same project (it's very handy this web and ejb cohabitation ...) I added a servlet using the @WebServlet annotation.

In the servlet, I used the @EJB annotation to obtain a reference to the @Singleton and displayed the result of calling its getTestVal method on the page.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sab.demo;

import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author sbutton
 */
@WebServlet(name = "TestServlet", urlPatterns = {"/TestServlet", "/test"})
public class TestServlet extends HttpServlet {

    @EJB
    TestSingletonBean singleton;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            out.println("");
            out.println("");
            out.println("<title>Servlet TestServlet</title>");
            out.println("");
            out.println("");
            out.println("<h1>Servlet TestServlet at " + request.getContextPath() + "</h1>");
            out.printf("<p>Singleton TESTVAL: %s</p>", singleton.getTestVal());
            out.println("");
            out.println("");
        } finally {
            out.close();
        }
    }
}

7. Calling this from a browser shows the value of TESTVAL to be that set in the init method.


So in summary, this simple example shows WebLogic Server 12c supporting the EJB @Singleton and @Startup semantics correctly.