I'm currently working on an application that caches a lot of state in memory and needs to do some things when it gets undeployed to make sure that state isn't lost. At first, I was using a ServletContextListener to do the cleanup. That was fine when the application was a WAR, but it doesn't work when the application is an EAR. Specifically, an attempt to call an EJB from the listener's contextDestroyed() method fails with:
javax.ejb.EJBException: JBAS014559: Invocation cannot proceed as component is shutting down
I then tried moving the shutdown code to a CDI bean and using @PreDestroy, and got the same result when attempting to call the EJB. Finally, I discovered that, for a @Singleton EJB with @DependsOn, the container is required to have the depended-on EJBs available during @PreDestroy.
So that is my current solution, but it got me wondering what the specifications say about injections during deployment shutdown. I looked through various EE specifications and could only find one other guarantee (besides the @Singleton @DependsOn guarantee mentioned previously) where @PreDestroy is concerned. Namely, the CDI specification says that any @Dependent-scoped objects must be destroyed after the CDI bean's @PreDestroy is called.
Have I missed something in other specifications, or are the EE specifications really this vague about dependency injection and @PreDestroy? It seems like an odd oversight, given that several specifications go out of their way to state that @PostConstruct is always called after all injections are completed.
Regardless of what the specifications say, the actual behavior on AS 7.2.0 is a little quirky. It seems like the EJB subsystem gets shut down before other subsystems, so you can't use an EJB during the shutdown of any other subsystem. This includes CDI, as previously mentioned, which is a little annoying. It also seems that you can't use an EJB from another EJB's @PreDestroy, unless said EJB is @Singleton and has a @DependsOn relationship with the first EJB. CDI doesn't seem to have this problem, at least for @ApplicationScoped beans relying on other @ApplicationScoped beans. And since EJB shutdown seems to happen before CDI shutdown, you can use CDI beans from EJB @PreDestroy methods with no problems.
Does anyone know if this behavior is defined somewhere? Or is it an unreliable implementation detail?