[hibernate-dev] CDI integration in Hibernate ORM and the Application scope
Yoann Rodiere
yoann at hibernate.org
Wed Dec 20 07:50:35 EST 2017
Hello all,
TL;DR: Application-scoped beans cannot be used as part of the @PreDestroy
method of ORM-instantiated CDI beans, and it's a bit odd because they can
be used as part of the @PostConstruct method.
I've been testing the CDI integration in Hibernate ORM for the past few
days, trying to integrate it into Search. I think I've discovered something
odd: when CDI-managed beans are destroyed, they cannot access other
Application-scoped CDI beans anymore. Not sure whether this is a problem or
not, so maybe we should discuss it a bit before going forward with the
current behavior.
Short reminder: scopes define when CDI beans are created and destroyed.
@ApplicationScoped is pretty self-explanatory: created when the application
starts and destroyed when it stops. Some other scopes are a bit more
convoluted: @Singleton basically means created *before* the application
starts and destroyed *after* the application stops (and also means "this
bean shall not be proxied"), @Dependent means created when an instance is
requested and destroyed when the instance is released, etc.
The thing is, Hibernate ORM is typically started very early and shut down
very late in the CDI lifecycle - at least within WildFly. So when Hibernate
starts, CDI Application-scoped beans haven't been instantiated yet, and it
turns out that when Hibernate ORM shuts down, CDI has already destroyed
Application-scoped beans.
Regarding startup, Steve and Scott solved the problem by delaying bean
instantiation to some point in the future when the Application scope is
active (and thus Application-scoped beans are available). This makes it
possible to use Application-scoped beans within ORM-instantiated beans as
soon as the latter are constructed (i.e. within their @PostConstruct
methods).
However, when Hibernate ORM shuts down, the Application scope has already
been terminated. So when ORM destroys the beans it instantiated, those
ORM-instantiated beans cannot call a method on referenced
Application-scoped beans (CDI proxies will throw an exception).
All in all, the only type of beans we can currently use in a @PreDestroy
method of an ORM-instantiated bean is @Dependent beans. @Singleton beans
will work, but only because they are not proxied and thus you can cheat and
use them even after they have been destroyed... which I definitely wouldn't
recommend.
I see two ways to handle the issue:
1. We don't change anything, and simply document somewhere that beans
instantiated as part of the CDI integration are instantiated within the
Application scope, but are destroyed outside of it. And we suggest that any
bean used in @PostDestroy method in an ORM-instantiated bean (directly or
not) must have either a @Dependent scope, or a @Singleton scope and no
@PostDestroy method.
2. We implement an "early shut-down" somehow, which would bring forward
bean destruction to some time when the Application scope is still active.
#1 may be enough for now, even though the behavior feels a bit odd, and
forces users to resort to less-than-ideal practices (using a @Singleton
bean after it has been destroyed).
#2 would require changes in WildFly and may be a bit complex. In
particular, if we aren't careful, Application-scoped beans may not be able
to use Hibernate ORM from within their @PreDestroy methods... Which is
probably not a good idea. So we would have to find a solution together with
the WildFly team. Also to be considered: Hibernate Search would have to be
shut down just before the "early shut-down" of Hibernate ORM occurs,
because Hibernate Search cannot function at all without the beans it
retrieves from the CDI context.
Thoughts?
Yoann Rodière
Hibernate NoORM Team
yoann at hibernate.org
More information about the hibernate-dev
mailing list