Skip to content

Conversation

@Ladicek
Copy link
Member

@Ladicek Ladicek commented Nov 18, 2025

Fixes #876

@Ladicek Ladicek added this to the CDI 5.0 milestone Nov 18, 2025
@Ladicek
Copy link
Member Author

Ladicek commented Nov 18, 2025

This is a draft because it also includes the @Eager commits (that are also present in #911). Please ignore the first 2 commits and only look at the last.

I'd especially welcome review of the changes to the Portable Extensions API, because I'm not familiar with those.

This annotation may be put on `@ApplicationScoped` beans to trigger eager
initialization. This occurs at the same time as the `Startup` event.

Putting the annotation on a bean of any other scope leads to definition
error. This may be relaxed in the future, if we find suitable meaning.

For example, eagerly initializing `@RequestScoped` beans typically
only makes sense for _some_ beans, depending on the nature of the request
(such as the URL in case of an HTTP request). My personal opinion is
that such conditions are best expressed in code, which is already
possible, because all beans can declare observer methods, which may
include arbitrary code.

`@Eager` is a shortcut for such observer in the most common scenario.
It also serves as a direct replacement of EJB `@Startup`, which also
only makes sense in case of application-wide beans (EJB `@Singleton`).
This annotation marks _auto-closeable_ beans. If the class of an instance
of auto-closeable bean implements `AutoCloseable`, the `close()` method
is called during bean destruction (after `@PreDestroy` callbacks or
disposer method invocation, but before destroying dependent instances).
@Azquelt
Copy link
Member

Azquelt commented Dec 1, 2025

Just to check I have this right:

  • A bean can be auto-closable, because it has the @AutoClose annotation, but not implement AutoClosable, in which case nothing happens.
  • AutoClosable does not need to be one of the bean types. It's sufficient for the contextual instance to implement AutoClosable.
  • The order of operations when destroying a bean is:
    • call PreDestroy lifecycle callback interceptor methods
    • destroy the bean instance
      • call the disposer method (for producer methods)
    • call AutoClosable.close
    • destroy any dependent objects

I'm having trouble working out the order of operations for auto-closable synthetic beans. I originally had this:

  • call PreDestroy lifecycle callback interceptor methods
  • destroy the bean instance
    • call the disposer method (for producer methods)
    • call Contextual.destroy (for portable extension synthetic beans)
    • call SyntheticBeanDisposer.dispose (for lite extension synthetic beans)
  • call AutoClosable.close
  • destroy any dependent objects

However, Contextual.destroy says that implementations should call CreationalContext.release to destroy dependent objects, so we'd need to call AutoClosable.close before that?

@Ladicek
Copy link
Member Author

Ladicek commented Dec 2, 2025

  • A bean can be auto-closable, because it has the @AutoClose annotation, but not implement AutoClosable, in which case nothing happens.

Correct.

  • AutoClosable does not need to be one of the bean types. It's sufficient for the contextual instance to implement AutoClosable.

Correct.

  • The order of operations when destroying a bean is:
    • call PreDestroy lifecycle callback interceptor methods
    • destroy the bean instance
      • call the disposer method (for producer methods)
    • call AutoClosable.close
    • destroy any dependent objects

This is a bit more involved, but essentially correct. Note that "destroying an instance of a bean" is what happens during Contextual.destroy(). It is:

  1. Call the @PreDestroy life cycle callbacks in case of managed beans. Call the disposer method in case of producer beans. Call the disposal callback in case of synthethic beans.
  2. Call AutoCloseable.close() in case the bean is auto-closeable and the class of contextual instance implements AutoCloseable.
  3. Destroy dependent instances.

The following is wrong. I covered synthetic beans above, but I'll cover the issues here as well:

I'm having trouble working out the order of operations for auto-closable synthetic beans. I originally had this:

  • call PreDestroy lifecycle callback interceptor methods

No. There are no @PreDestroy callbacks for synthetic beans.

  • destroy the bean instance
    • call the disposer method (for producer methods)

No. There are no disposer methods for synthetic beans, synthetic beans are not producer methods. Instead, we call the disposer callback as configured through the Portable Extensions configurator API / through the Build Compatible Extensions API.

If the user provided a custom Bean implementation, they are on their own.

* call `Contextual.destroy` (for portable extension synthetic beans)

Hard NO! Contextual.destroy() does this entire process, it's not called as part of it. As mentioned above, we call the disposer callback as configured.

* call `SyntheticBeanDisposer.dispose` (for lite extension synthetic beans)

Right, as mentioned above.

  • call AutoClosable.close

Right.

  • destroy any dependent objects

Right.

However, Contextual.destroy says that implementations should call CreationalContext.release to destroy dependent objects, so we'd need to call AutoClosable.close before that?

I think I covered this above. The main misconception comes from the nature of Contextual.destroy(): it is not called as part of bean instance destruction process -- it is the bean instance destruction process.

@Azquelt
Copy link
Member

Azquelt commented Dec 3, 2025

* call `Contextual.destroy` (for portable extension synthetic beans)

Hard NO! Contextual.destroy() does this entire process, it's not called as part of it. As mentioned above, we call the disposer callback as configured.

Aha, this was the bit that I was confused by, having previously had to do a custom Bean implementation.

It seemed odd to have an isAutoClose() method on Bean if the user had to also implement it themselves in destroy, but I guess in most cases they won't, as they should use BeanConfigurator instead in which case the container calls their dispose or destroy callback at the right time and will also call close() for auto-closable beans.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AutoCloseable beans

2 participants