jbossejbstateless-session-beanpostconstructstateful-session-bean

@PostConstruct called on Stateful EJB invocation but not Stateless Why?


This question is an offshoot of another that I posted a couple of weeks ago: log4j2 logging of code in EJB jar on JBoss EAP 7. In that post I posed a problem and eventually a solution for logging initialization on EJBs deployed as EJB jars (not EARs) onto a JBoss EAP 7 Server and invoked from another servlet. These EJBs are invoked through local interface.

The solution I presented in that link worked beautifully for the first EJB I tried it with, a Stateful EJB. the @PostConstruct-annotated method is called and initializes the logging context and everything works great.

The solution failed on the second EJB I tried it with. This EJB was stateless. @PostConstruct method is never called and the first attempt at logging blows the thing up because logger is null. The only difference I could see between the two beans was that the second one was stateless whereas the first was stateful. As an experiment, I made the second one stateful. Once I did that, @PostConstruct was called, logging got initialized and everything was basically fine.

According to the Oracle JavaEE6 tutorial, @PostConstruct method is supposed to be called on stateless bean instantiation. So, why does stateful session bean instantiation call @PostConstruct while stateless session bean instantiation does not, and what might I do about it?

Thanks.

Update: Adding Source Code.

ejb-jar.xml

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         version="3.2"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd">
    <module-name>DealerLocatorBean</module-name>
    <enterprise-beans>
        <session>
            <ejb-name>DealerLocatorBean</ejb-name>
            <home>com.whatever.ServiceLogicHome</home>
            <remote>com.whatever.ServiceLogic</remote>
            <local-home>com.whatever.ServiceLogicLocalHome</local-home>
            <local>com.whatever.ServiceLogicLocal</local>
            <ejb-class>com.whatever.ejbs.DealerLocatorBean</ejb-class>
            <session-type>Stateless</session-type>
            <!-- <session-type>Stateful</session-type> No problem if this is made stateful-->
            <transaction-type>Bean</transaction-type>
        </session>
    </enterprise-beans>
</ejb-jar>

DealerLocatorBean.java:

public class DealerLocatorBean implements SessionBean
{

    private static final String LOGGER_CONFIG = "/path/to/log4j2.xml";
    private static final String LOGGER_CONTEXT_NAME = "VTDLLOC-EJB";
    private static LoggerContext logctx;
    private static Logger logger = null;

    public DealerLocatorBean() {
        System.out.println("calling DealerLocatorBean() constructor");
    }
    @PostConstruct
    @TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
    private void postConstruct() {
        System.out.println("DealerLocatorBean.postConstruct()");
        logctx = Configurator.initialize(LOGGER_CONTEXT_NAME, LOGGER_CONFIG);
        logger = logctx.getLogger(getClass().getName());
        logger.log(Level.INFO, ("postConstruct() in DealerLocatorBean called"));
        logger.log(Level.INFO, ("******END OF THE postConstruct() CALL******"));
    }

    @PreDestroy
    @TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
    private void preDestroy() {
        logger.log(Level.INFO, ("preDestroy() in DealerLocatorBean called.  Shutting down logging."));
        Configurator.shutdown(logctx);
    }

If the bean is deployed as stateful (in ejb-jar.xml), @postConstruct is called the first time the bean is used after deployment and everything works. DealerLocatorBean.postConstruct() is seen in the output and all subsqeuent logging works.

If the bean is deployed as stateless (in ejb-jar.xml), @postConstruct is never called. DealerLocatorBean.postConstruct() is NOT seen in the output. Logging is not initialized, and NullPointerExceptions result as soon as the code tries to log something through logger.


Solution

  • Have you seen this bean reported to the logs as deployed? Also not final statics are not allowed in SLSBs. I would suggest to change private static LoggerContext logctx; to private static final LoggerContext logctx= Configurator.initialize(LOGGER_CONTEXT_NAME, LOGGER_CONFIG); if possible and the same for logger and remove the corresponding statements out of @PostConstruct or just remove the static keyword in the declarations of logctx and logger.