Chapter 5. Web Bean lifecycle

The lifecycle of a Web Bean instance is managed by the Web Beans context object for the Web Bean's scope. The context implementation collaborates with the Web Bean manager via the Context and Bean interfaces to create and destroy Web Bean instances.

The actual mechanics of Web Bean creation and destruction varies according to what kind of Web Bean it is:

When the Web Bean manager injects dependencies or resolves EL names, and there is no existing instance of the Web Bean cached by the context object for the Web Bean scope, the context object automatically creates a new instance of the Web Bean. When a Web Beans context is destroyed, the context object automatically destroys any instances associated with that context.

5.1. Creation

The Bean.create() method is responsible for creating new instances of a Web Bean.

public abstract class Bean<T> {
    
    public abstract T create();
    
    ...
    
}

The create() method performs the following tasks:

  • obtains an instance of the Web Bean,

  • creates the interceptor and decorator stacks and binds them to the instance,

  • injects any dependencies,

  • sets any initial field values defined in XML, and

  • calls the @PostConstruct method, if necessary.

If any exception occurs while creating an instance, the exception is rethrown by the create() method. If the exception is a checked exception, it is wrapped and rethrown as an (unchecked) CreationException.

5.2. Destruction

The Bean.destroy() method is responsible for destroying instances of a Web Bean.

public abstract class Bean<T> {
    
    public abstract void destroy(T instance);
    
    ...
    
}

The destroy() method performs the following tasks:

If any exception occurs while destroying an instance, the exception is caught by the destroy() method.

If the application invokes a Web Bean instance after it has been destroyed, the behavior is undefined.

5.3. Lifecycle of simple Web Beans

An instance of a simple Web Bean is completely under the control of the Web Bean manager.

When the create() method is called:

  • First, the Web Bean manager calls the Web Bean constructor to obtain an instance of the Web Bean. For each constructor parameter, the Web Bean manager passes the object returned by Manager.getInstanceByType(). The manager is permitted to return an instance of a manager-generated subclass of the Web Bean implementation class, allowing interceptor and decorator bindings.

  • Next, the Web Bean manager initializes the values of any attributes annotated @EJB, @PersistenceContext or @Resource, as defined in the Common Annotations for the Java Platform and EJB 3.0 specifications.

  • Next, the Web Bean manager initializes the values of all injected fields. For each injected field, the Web Bean manager sets the value to the object returned by Manager.getInstanceByType().

  • Next, the Web Bean manager initializes the values of any fields with initial values specified in XML, as defined in Section 9.2.5, “Field initial value declarations”.

  • Next, the Web Bean manager calls all initializer methods. For each initializer method parameter, the Web Bean manager passes the object returned by Manager.getInstanceByType().

  • Next, the Web Bean manager calls the @PostConstruct method, if any.

  • Finally, the Web Bean manager builds the interceptor and decorator stacks for the instance as defined in Section 6.2.10, “Interceptor stack creation” and Section 6.3.8, “Decorator stack creation” and binds them to the instance.

When the destroy() method is called:

  • The Web Bean manager calls the @PreDestroy method, if any.

  • Finally, the Web Bean manager destroys dependent objects.

5.4. Lifecycle of stateful session enterprise Web beans

The Web Bean manager and the EJB container share control of instances of enterprise Web Beans that are stateful session beans.

When the create() method is called, the Web Bean manager creates and returns an enterprise bean proxy, as defined in Section 3.3.8, “Enterprise bean proxies”.

When the destroy() method is called, the Web Bean manager calls the Web Bean remove method upon the proxy. For each remove method parameter, the Web Bean manager passes the object returned by Manager.getInstanceByType(). If the enterprise Web Bean has no Web Bean remove method, the Web Bean manager throws an UnremovedException.

Open issue: this exception will just be caught and logged by the Web Bean manager!

Note that the Web Bean manager intercepts the @PostConstruct and @PreDestroy callbacks of any EJB and performs additional work, as defined in Section 5.8, “Lifecycle of EJB beans”

5.5. Lifecycle of stateless session and singleton enterprise Web Beans

The EJB container always controls the lifecycle of all stateless session and singleton bean instances. However, for instances of enterprise Web Beans, the Web Bean manager controls the lifecycle of the EJB local object reference.

When the create() method is called, the Web Bean manager creates and returns an enterprise bean proxy, as defined in Section 3.3.8, “Enterprise bean proxies”.

When the destroy() method is called, the Web Bean manager simply discards the proxy and all EJB local object references.

Note that the Web Bean manager intercepts the @PostConstruct and @PreDestroy callbacks and performs additional work, as defined in Section 5.8, “Lifecycle of EJB beans”

5.6. Lifecycle of producer methods

Any Java object may be returned by a producer method. It is not required that the returned object be an instance of another Web Bean. However, if the returned object is not an instance of another Web Bean, the Web Bean manager will provide none of the following capabilities:

  • injection of other Web Beans

  • lifecycle callbacks

  • method and lifecycle interception

In the following example, the producer method returns instances of other Web Beans:

@SessionScoped
public class PaymentStrategyProducer {
   
   private PaymentStrategyType paymentStrategyType;
   
   public 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, the object returned by the producer method has already had its dependencies injected, receives lifecycle callbacks and has interception enabled.

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

@SessionScoped
public class PaymentStrategyProducer {
   
   private PaymentStrategyType paymentStrategyType;

   public 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, the object returned by the producer method will not have any dependencies injected by the Web Bean manager, receives no lifecycle callbacks and does not have interception enabled.

When the create() method is called, the Web Bean manager must:

  • obtain the Bean object for the most specialized Web Bean that specializes the Web Bean which declares the producer method, and then

  • obtain an instance of the most specialized Web Bean, by calling Manager.getInstance(), passing the Bean object representing the Web Bean, and

  • invoke the producer method upon this instance, passing to each parameter the object returned by Manager.getInstanceByType().

The return value of the producer method, after method interception completes, is the new Web Bean instance to be returned by Bean.create().

If the producer method returns a null value and the producer method Web 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 disposal method for this producer method, the Web Bean manager must:

  • obtain the Bean object for the most specialized Web Bean that specializes the Web Bean which declares the disposal method, and then

  • obtain an instance of the most specialized Web Bean, by calling Manager.getInstance(), passing the Bean object representing the Web Bean, and

  • invoke the disposal method upon the this instance, passing the object returned by Manager.getInstanceByType() to each parameter.

Finally, the Web Bean manager destroys dependent objects.

5.7. Lifecycle of JMS endpoints

The Web Bean manager completely controls the lifecycle of any JMS endpoint instance. An instance of a JMS endpoint is a proxy object, provided by the Web Bean manager, that implements all the API types defined in Section 3.5, “JMS endpoints”, delegating the actual implementation of these methods directly to the underlying JMS objects obtained via JNDI lookup and JMS APIs.

A JMS endpoint proxy object is a dependent object of the object it is injected into.

JMS endpoint proxy objects are serializable.

When the create() method is called, the Web Bean manager creates and returns a special proxy object that implements all the API types of the JMS endpoint.

The methods of this proxy object delegate to JMS objects obtained as needed via JNDI lookup and JMS APIs.

  • The Destination is obtained by JNDI lookup, using the JNDI name defined in <destination>.

  • The ConnectionFactory is obtained by JNDI lookup, using the JNDI name defined in <connectionFactory>.

  • The Connection is obtained by calling QueueConnectionFactory.createQueueConnection() or TopicConnectionFactory.createTopicConnection(). The Web Bean manager is permitted to share a connection between multiple proxy objects.

  • The Session object is obtained by calling QueueConnection.createQueueSession() or TopicConnection.createTopicSession().

  • The MessageProducer object is obtained by calling QueueSession.createSender() or TopicSession.createPublisher().

When the destroy() method is called, the Web Bean manager must ensure that all JMS objects created by the proxy object are destroyed by calling close() if necessary.

  • The Connection is destroyed by calling Connection.close() if necessary. If the connection is being shared between multiple proxy objects, the Web Bean manager is not required to close the connection when the proxy is destroyed.

  • The Session object is destroyed by calling Session.close().

  • The MessageProducer object is destroyed by calling MessageProducer.close().

The close() method of a JMS endpoint proxy object always throws an UnsupportedOperationException.

5.8. Lifecycle of EJB beans

From time to time the EJB container creates EJB bean instances. The Web Bean manager must perform dependency injection upon any EJB session, singleton, or message driven bean instance that executes in the context of a Web Beans application, regardless of whether it is a Web Bean instance.

When the EJB container creates a new instance of an EJB bean, the Web Bean manager intercepts the @PostConstruct callback and performs the following steps, before the callback is allowed to proceed to the bean instance.

  • First, The Web Bean manager initializes the values of all injected fields. For each injected field, the Web Bean manager sets the value to the object returned by Manager.getInstanceByType().

  • Next, if the EJB bean instance is an instance of a Web Bean, the Web Bean manager initializes the values of any fields with initial values specified in XML, as defined in Section 9.2.5, “Field initial value declarations”.

  • Next, the Web Bean manager calls all initializer methods. For each initializer method parameter, the Web Bean manager passes the object returned by Manager.getInstanceByType().

  • Finally, the Web Bean manager builds the interceptor and decorator stacks for the instance as defined in Section 6.2.10, “Interceptor stack creation” and Section 6.3.8, “Decorator stack creation” and binds them to the instance.

Open issue: we need to make sure that the Web Bean manager has fully initialized before singleton EJB beans are instantiated.

When the EJB container destroys an instance of an EJB bean, the Web Bean manager intercepts the @PreDestroy callback and destroys all dependent objects, after the callback returns from the bean instance.

5.9. Lifecycle of Servlets

The Servlet container creates instances of Servlets. The Web Bean manager must perform dependency injection upon any Servlet that executes in the context of a Web Beans application.

When the Servlet container creates a new instance of a Servlet, the Web Bean manager performs the following steps.

  • First, the Web Bean manager initializes the values of all injected fields. For each injected field, the Web Bean manager sets the value to the object returned by Manager.getInstanceByType().

  • Next, the Web Bean manager calls all initializer methods. For each initializer method parameter, the Web Bean manager passes the object returned by Manager.getInstanceByType().

When the Servlet container destroys a Servlet, the Web Bean manager destroys all dependent objects.

Open issue: currently there is no way to intercept creation or destruction of Servlets. We need a new API from the Servlet specification.

Open issue: we need to make sure that the Web Bean manager has fully initialized before Servlets are instantiated.

In a Java EE 5 environment, the Web Bean manager is not required to support injected fields or initializer methods of Servlets.