An Introduction to the Enterprise JavaBeans 3.0 (EJB 3) Specification

Dependency Injections

A bean declares a dependency upon a resource or other entry in its environment context through a dependency annotation. A dependency annotation specifies the type of object or resource on which the bean is dependent, its characteristics, and the name through which it is to be accessed.

The following are examples of dependency annotations:



    @EJB(name="mySessionBean", beanInterface=MySessionIF.class)
    
    @Resource(name="myDB", type="javax.sql.DataSource.class")
    

Dependency annotations may be attached to the bean class or to its instance variables or methods. The amount of information that needs to be specified for a dependency annotation depends upon its usage context and how much information can be inferred from that context.

Injecting arbitrary resources with @Resource

The @EJB annotation only injects EJB stubs. A more generic dependency injection annotation is @Resource. Using the @Resource annotation, you can inject any service object from the JNDI using the object's JNDI name. Both global (java:/) and local (java:comp/env) JNDI trees are searched. The following examples inject a messaging connection factory and a messaging queue:



    @Resource (name="ConnectionFactory") QueueConnectionFactory factory;
    
    @Resource (name="queue/A") Queue queue;
    

For "well-known" objects such as TimerService and SessionContext, the JNDI names are standard, and therefore the @Resource annotation can inject these objects without an explicit specification of the "name" attribute:



    @Resource TimerService tms;
    
    @Resource SessionContext ctx;
    

Similar to the @EJB annotation, the @Resource annotation can be applied to setter methods, and the @Resources annotation can be applied to arrays. Both the @EJB and @Resource annotations are specifically tailored to the resources they inject. They simplify the developer's work.

Code sample

In the example below, the variable customerDB will be assigned a DataSource object with JNDI name myDB. The "name" attribute needs to be specified because the name of the variable we have chosen, customerDB, is different from the JNDI name myDB. The "type" attribute does not need to be specified because it can be derived from the type of the variable (for example, DataSource):



    @Stateless public class MySessionBean implements MySession {
    
    //type is inferred from variable
    @Resource(name="myDB") public DataSource customerDB;
    
    public void myMethod1(String myString){
    try  {
      Connection conn = customerDB.getConnection();
      ...
    catch (Exception ex)
      }
    }
    

Changes to the Four Types of Enterprise Beans

As we all know, there are four kinds of EJBs, and needless  to say, EJB 3.0 made some changes to each type of EJB. In this section, we will look at the changes proposed for each type of EJB. One of the main advantages is that in EJB 3.0, all the managed service objects are POJOs (for example, session beans) or very lightweight components (such as message-driven beans). As you'll see, EJB 3.0 has made the development of EJBs much easier and simpler.

Stateless Session Beans

An EJB 3.0 session bean is a POJO managed by the EJB container.

The functionality of a session bean is defined by its service interface (a.k.a. business interface), which is a plain old Java interface. Using the interface class name, the session bean client retrieves a stub object of the bean from the server's JNDI. The stub object implements the bean's service interface. The client can then make calls to the bean interface methods against the stub object. The stub object simply passes the calls to the actual bean instance objects in the container, which have the implementations of those methods and do the actual work. The stub object is automatically generated by the EJB container, and it knows how to route the bean method calls to the container—you do not need to provide an implementation for the stub object. In a stateless session bean, the client-side stub object can route your method call to any bean instance that happens to be available in the container-managed object pool. Therefore, you should not have any field variables to store the bean state in the bean class.

Business interfaces

Business interfaces are required for stateless session beans. It is not always necessary to define one. When undefined, they will be automatically generated for you. The type of generated interface, either local or remote, is dependent on the annotation you used in the bean class and will be a local interface if there is no annotation. All the public methods of the bean class will be included as part of the automatically generated business interface.

Home interfaces

Stateless session beans do not need home interfaces. The client may acquire a reference to a stateless session bean by means of injection or annotation of variables.

Bean class

A stateless session bean must be annotated with the stateless annotation or denoted in the deployment descriptor as a stateless session bean. The bean class need not implement the javax.ejb.SessionBean interface. The @Stateless annotation indicates that this bean is a stateless session bean:



    @Stateless
    public class TraderBean implements Trader {
    public void buy (String symbol, int quantity){
    System.out.println("Buying "+quantity+ " of "+ symbol);
    }
    public void sell (String symbol, int quantity);{
    System.out.println("Selling "+quantity+ " of "+ symbol);
    }
    }
    

The session bean client

Once the session bean is deployed into the EJB 3.0 container, a stub object is created, and it is registered in the server's JNDI registry. The client code obtains a stub of the bean using the class name of the interface in the JNDI. Below is an example on how to retrieve a stub instance of the TraderBean for this JSP page. You can make method calls against the stub object, and the call is transparently delegated to the bean instance in the EJB 3.0 container:



    private Trader tr = null;
    public void initialize () {
        try {
          InitialContext ctx = new InitialContext();
          tr = (Trader) ctx.lookup(
                      Trader.class.getName());
        }catch (Exception e) {
          e.printStackTrace ();
        }
    }
    // ... ...
    public void service (Request req, Response rep) {
        // ... ...
        double res = tr.buy("SNPS",1000);
    }
    

Callbacks for stateless session beans

The following life cycle event callbacks are supported for stateless session beans:

  • PostConstruct
  • PreDestroy

The PostConstruct callback occurs after any dependency injection has been performed by the container and before the first business method invocation on the bean. The PostConstruct method is invoked in an unspecified transaction context and security context.

The PreDestroy callback occurs at the time the bean instance is destroyed. The PreDestroy method executes in an unspecified transaction and security context.

Remote and local interfaces

A session bean can also implement multiple interfaces, each interface targeting a different type of client. By default, the interface is for a "local" client that runs in the same JVM as the EJB 3.0 container. Method call invocations over Java references are fast and efficient. Another type of session bean interface, the remote interface, is for remote clients. When a client looks up the session bean stub via the remote interface, the container returns a serialized stub object that implements the remote interface. The remote stub knows how to pass remote procedure calls (RPCs) to the server, even in a clustered environment. The remote interface is also a plain old Java interface.

Note that using the remote interface involves the serialization and deserialization of the stub, and all calls to the bean instance are made over the network. This approach is considerably less efficient than using the local interface. You should avoid looking up a remote interface from a local client.

In the session bean implementation, you can use the @Local and @Remote annotations to specify the local and remote interfaces for this bean. Here is an example bean that implements both a local and remote interface:



    @Stateless
    @Local ({Trader.class})
    @Remote ({RemoteTrader.class})
    public class TraderBean implements Trader, RemoteTrader {
    
      public void buy (String symbol, int quantity){
        System.out.println("Buying "+quantity+ " of "+ symbol);
      }
    
      public void sell (String symbol, int quantity);{
        System.out.println("Selling "+quantity+ " of "+ symbol);
      }
    }
    

The @Local and @Remote annotations can also be used to tag session bean interfaces instead of the bean implementation class. For instance, the following code snippet specifies that the RemoteTrader is a remote interface. With that, you no longer need the @Remote tag on TraderBean.