There are times when you need some startup code to run in the same JVM as your deployed J2EE application. This may be for the purposes of initializing certain classes, or to start services that would otherwise violate EJB programming restrictions. In the latter case, the code must run in the same JVM as the EJBs, but outside the EJB container.
One solution is to create an abstract parent class that all of your session beans extend. This is a good idea regardless, because the abstract class can provide empty implementations for most of the methods of the SessionBean interface, simplifying your session bean classes. For purposes of initialization, the abstract class can have a static block that perfoms the needed startup actions. This works as long you are following the Session Facade design pattern. If all clients access the EJB container through session beans, then you are guaranteed that the classloader will load the abstract parent class before any methods of the session beans are executed.
Although the abstract parent class static block concept can be used to execute startup code, there are times when you want to start services that violate EJB programming restrictions, and therefore must be executed outside of the EJB container (but not outside of the application's JVM).
One way to execute startup code outside of the EJB container is to use servlets. In the Servlet 2.3 spec, ServletContextListeners were introduced. Implement one of those and enter it an a war's web.xml file. Then add this war file to the same ear that contains your ejb-jar files. Then, you can trigger startup from the contextInitialized() method and shutdown from the contextDestroyed() method. Here's an example:
web.xmlOne advantage of this approach is that it's a standard J2EE way of implementing startup/shutdown hooks for J2EE applications, and is therefore app server agnostic. One disadvantage is that it assumes that your servlet container is running in the same JVM as your EJB container. Oftentimes you will have the web tier running on a different machine from the ejb tier, within a DMZ protected by firewalls. If this is the case, the servlet approach is not an option.<context-param>
<param-name>i18nResources</param-name>
<param-value>/WEB-INF/application.properties</param-value>
</context-param>
<listener>
<listener-class>MyListener</listener-class>
</listener>Listener
public class MyListener implements javax.servlet.ServletContextListener {
public void contextDestroyed(ServletContextEvent e) {}public void contextInitialized(ServletContextEvent e) {
// Startup code goes here.ServletContext ctx = e.getServletContext()
String pathToProperties = ctx.getInitParameter("i18nResources");
...
}
}
So now we're looking for a way to have startup code executed within the same JVM as the EJBs, but outside of both the EJB and servlet containers. Unfortunately, there is no app server agnostic solution.
WebLogic provides "startup classes" for this purpose.
JBoss allows one to bind JMX MBeans to the EJB container's environment. See Using JMX to Initialize JBoss App. for more information on this approach.
Posted by tomlauren at November 13, 2003 03:48 PM