Chapter 7. Lifecycle of contextual instances

The lifecycle of a contextual instance of a bean is managed by the context object for the bean's scope, as defined in Chapter 6, Scopes and contexts.

Every bean in the system is represented by an instance of the Bean interface defined in Section 11.1, “The Bean interface”. This interface is a subtype of Contextual. To create and destroy contextual instances, the context object calls the create() and destroy() operations defined by the interface Contextual, as defined in Section 6.1, “The Contextual interface”.

7.1. Restriction upon bean instantiation

The managed bean and EJB specifications place very few programming restrictions upon the bean class of a bean. In particular, the class is a concrete class and is not required to implement any special interface or extend any special superclass. Therefore, bean classes are easy to instantiate and unit test.

However, if the application directly instantiates a bean class, instead of letting the container perform instantiation, the resulting instance is not managed by the container and is not a contextual instance as defined by Section 6.5.2, “Contextual instance of a bean”. Furthermore, the capabilities listed in Section 2.1, “Functionality provided by the container to the bean” will not be available to that particular instance. In a deployed application, it is the container that is responsible for instantiating beans and initializing their dependencies.

If the application requires more control over instantiation of a contextual instance, a producer method or field may be used. Any Java object may be returned by a producer method or field. It is not required that the returned object be a contextual reference for a bean. However, if the object is not a contextual reference for another bean, the object will be contextual instance of the producer method bean, and therefore available for injection into other objects and use in EL expressions, but the other capabilities listed in Section 2.1, “Functionality provided by the container to the bean” will not be available to the object.

In the following example, a producer method returns instances of other beans:

@SessionScoped
public class PaymentStrategyProducer implements Serializable {
   
   private PaymentStrategyType paymentStrategyType;
   
   public void setPaymentStrategyType(PaymentStrategyType type) {
      paymentStrategyType = type;
   }

   @Produces PaymentStrategy getPaymentStrategy(@CreditCard PaymentStrategy creditCard,
                                                @Cheque PaymentStrategy cheque,
                                                @Online PaymentStrategy online) {
      switch (paymentStrategyType) {
         case CREDIT_CARD: return creditCard;
         case CHEQUE: return cheque;
         case ONLINE: return online;
         default: throw new IllegalStateException();
      }    
    }

}

In this case, any object returned by the producer method has already had its dependencies injected, receives lifecycle callbacks and event notifications and may have interceptors.

But in this example, the returned objects are not contextual instances:

@SessionScoped
public class PaymentStrategyProducer implements Serializable {
   
   private PaymentStrategyType paymentStrategyType;

   public void setPaymentStrategyType(PaymentStrategyType type) {
      paymentStrategyType = type;
   }

   @Produces PaymentStrategy getPaymentStrategy() {
      switch (paymentStrategyType) {
         case CREDIT_CARD: return new CreditCardPaymentStrategy();
         case CHEQUE: return new ChequePaymentStrategy();
         case ONLINE: return new OnlinePaymentStrategy();
         default: throw new IllegalStateException();
      }    
    }

}

In this case, any object returned by the producer method will not have any dependencies injected by the container, receives no lifecycle callbacks or event notifications and does not have interceptors or decorators.

7.2. Container invocations and interception

When the application invokes:

the invocation is treated as a business method invocation.

When the container invokes a method of a bean, the invocation may or may not be treated as a business method invocation:

  • Invocations of initializer methods by the container are not business method invocations.

  • Invocations of producer, disposer and observer methods by the container are business method invocations and are intercepted by method interceptors and decorators.

  • Invocation of lifecycle callbacks by the container are not business method invocations, but are intercepted by interceptors for lifecycle callbacks.

  • Invocation of EJB timer service timeouts by the container are not business method invocations, but are intercepted by interceptors for EJB timeouts.

  • Invocations of interceptors and decorator methods during method or lifecycle callback interception are not business method invocations, and therefore no recursive interception occurs.

  • Invocations of message listener methods of message-driven beans during message delivery are business method invocations.

If, and only if, an invocation is a business method invocation:

  • it passes through method interceptors and decorators, and

  • in the case of a session bean, it is subject to EJB services such as declarative transaction management, concurrency, security and asynchronicity, as defined by the EJB specification.

Otherwise, the invocation is treated as a normal Java method call and is not intercepted by the container.

7.3. Lifecycle of contextual instances

The actual mechanics of bean creation and destruction varies according to what kind of bean is being created or destroyed.

7.3.1. Lifecycle of managed beans

When the create() method of the Bean object that represents a managed bean is called, the container obtains an instance of the bean, as defined by the Managed Beans specification, calling the bean constructor as defined by Section 5.5.1, “Injection using the bean constructor”, and performing dependency injection as defined in Section 5.5.2, “Injection of fields and initializer methods”.

When the destroy() method is called, the container destroys the instance, as defined by the Managed Beans specification, and any dependent objects, as defined in Section 5.5.3, “Destruction of dependent objects”.

7.3.2. Lifecycle of stateful session beans

When the create() method of a Bean object that represents a stateful session bean that is called, the container creates and returns a container-specific internal local reference to a new session bean instance. The reference must be passivation capable. This reference is not directly exposed to the application.

Before injecting or returning a contextual instance to the application, the container transforms its internal reference into an object that implements the bean types expected by the application and delegates method invocations to the underlying stateful session bean instance. This object must be passivation capable.

When the destroy() method is called, and if the underlying EJB was not already removed by direct invocation of a remove method by the application, the container removes the stateful session bean. The @PreDestroy callback must be invoked by the container.

Note that the container performs additional work when the underlying EJB is created and removed, as defined in Section 5.5, “Dependency injection”

7.3.3. Lifecycle of stateless session and singleton beans

When the create() method of a Bean object that represents a stateless session or singleton session bean is called, the container creates and returns a container-specific internal local reference to the session bean. This reference is not directly exposed to the application.

Before injecting or returning a contextual instance to the application, the container transforms its internal reference into an object that implements the bean types expected by the application and delegates method invocations to the underlying session bean. This object must be passivation capable.

When the destroy() method is called, the container simply discards this internal reference.

Note that the container performs additional work when the underlying EJB is created and removed, as defined in Section 5.5, “Dependency injection”

7.3.4. Lifecycle of producer methods

When the create() method of a Bean object that represents a producer method is called, the container must invoke the producer method as defined by Section 5.5.4, “Invocation of producer or disposer methods”. The return value of the producer method, after method interception completes, is the new contextual instance to be returned by Bean.create().

If the producer method returns a null value and the producer method bean has the scope @Dependent, the create() method returns a null value.

Otherwise, if the producer method returns a null value, and the scope of the producer method is not @Dependent, the create() method throws an IllegalProductException.

When the destroy() method is called, and if there is a disposer method for this producer method, the container must invoke the disposer method as defined by Section 5.5.4, “Invocation of producer or disposer methods”, passing the instance given to destroy() to the disposed parameter. Finally, the container destroys dependent objects, as defined in Section 5.5.3, “Destruction of dependent objects”.

7.3.5. Lifecycle of producer fields

When the create() method of a Bean object that represents a producer field is called, the container must access the producer field as defined by Section 5.5.5, “Access to producer field values” to obtain the current value of the field. The value of the producer field is the new contextual instance to be returned by Bean.create().

If the producer field contains a null value and the producer field bean has the scope @Dependent, the create() method returns a null value.

Otherwise, if the producer field contains a null value, and the scope of the producer field is not @Dependent, the create() method throws an IllegalProductException.

7.3.6. Lifecycle of resources

When the create() method of a Bean object that represents a resource is called, the container creates and returns a container-specific internal reference to the Java EE component environment resource, entity manager, entity manager factory, remote EJB instance or web service reference. This reference is not directly exposed to the application.

Before injecting or returning a contextual instance to the application, the container transforms its internal reference into an object that implements the bean types expected by the application and delegates method invocations to the underlying resource, entity manager, entity manager factory, remote EJB instance or web service reference. This object must be passivation capable.

When the destroy() method is called, the container discards this internal reference and performs any cleanup required of state associated with the client or transaction.

The container must perform ordinary Java EE component environment injection upon any non-static field that functions as a resource declaration, as defined by the Java EE platform and Common Annotations for the Java platform specifications. The container is not required to perform Java EE component environment injection upon a static field. Portable applications should not rely upon the value of a static field that functions as a resource declaration.