Dependency and Resource Injection

EJBs provide basic Dependency and Resource Injection as first class services. Its possible to declare dependencies on other session beans as well as resources such as JMS destinations, Data sources etc.

Getting hold of fellow beans using @EJB

This annotation is used to declare a dependency on another session bean which can be a no-interface, local or a remote interface of an EJB. There is no need to refine this further (specify other elements on this annotation) if you all you have is a single EJB which can serve as the the candidate bean for the injection point. You can inject Stateless, Stateful as well as Singleton beans using this annotation

Message Driven Beans (MDB) are not eligible for direct reference/injection

In case there is more than one implementation for an EJB type, the beanName element of the @EJB annotation can be used to further narrow down the instance to be injected and it takes into account the value of the (optional) name element in the @Stateful, @Stateless or @Singleton bean annotation

package ejbap.di_and_ri;

import javax.ejb.Stateless;

@Stateless(name = "CSVParserBean")
public class CSVParser implements Parser{

    @Override
    public String parse(String file) {
        return ""; //dummy
    }
}
package ejbap.di_and_ri;

import javax.ejb.EJB;
import javax.ejb.Stateless;

@Stateless
public class CSVParsingService {

    @EJB(beanName = "CSVParserBean", beanInterface = Parser.class)
    Parser parser;

    public String parse(String file){
        return parser.parse(file);
    }
}

The lookup element can be used to lookup a session bean using it's global JNDI name

EJB 3.1 introduced the notion of a portable global JNDI name syntax for looking up EJB components. This is leveraged by the lookup element. The global JNDI name syntax is as follows:

java:global[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>]

There are two more portable naming conventions based on application and module name. They have not been discussed to keep things simple

package ejbap.di_and_ri;

import javax.ejb.EJB;

public class AnotherTimeKeeperClient {

    @EJB(lookup = "java:global/ejbap/TimeKeeper")
    TimeKeeper timeKeeper;

    public String getDateTime(){
        return timeKeeper.dateTime();
    }
}

Either the beanName or the lookup element should be used to lookup session beans. It is illegal to use them together

In addition to existing EJBs, Servlets and JSF Managed Beans can also use this annotation to lookup/inject other session bean references

package ejbap.di_and_ri;

import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "TimeKeeperServlet", urlPatterns = {"/time"})
public class TimeKeeperServlet extends HttpServlet {

    @EJB
    TimeKeeper keeper;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        try (PrintWriter out = response.getWriter()) {
            out.println("<!DOCTYPE html>");
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Time Keeper Servlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h2>Time is " + keeper.dateTime() + "</h2>");
            out.println("</body>");
            out.println("</html>");
        }
    }

}

package ejbap.di_and_ri;

import javax.annotation.ManagedBean;
import javax.ejb.EJB;
import javax.faces.bean.RequestScoped;

@ManagedBean
@RequestScoped
public class TimeKeeperJSFController {

    @EJB
    TimeKeeper keeper;

    public String getDateTime(){
        return keeper.dateTime();
    }
}

@EJBs

This annotation is used to bind multiple EJB references to the JNDI naming context which you can later refer to by searching the JNDI tree again. Please note that this annotation is applicable to a class only

package ejbap.di_and_ri;

import javax.ejb.EJB;
import javax.ejb.EJBs;
import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.naming.NamingException;

@Stateless
@EJBs({
  @EJB(name = "CSVParserEJB", beanInterface = Parser.class, beanName = "CSVParser"),
  @EJB(name = "XMLParserEJB", beanInterface = Parser.class, beanName = "XMLParser")
})
public class MultipleEJBReferences {

    public Parser getXMLParser(){
        try {
            return lookup("java:comp/env/XMLParserEJB");
        } catch (NamingException ex) {
            throw new RuntimeException(ex);
        }
    }

    public Parser getCSVParser(){
        try {
            return lookup("java:comp/env/CSVParserEJB");
        } catch (NamingException ex) {
            throw new RuntimeException(ex);
        }
    }

    private Parser lookup(String jndiName) throws NamingException{
        return (Parser) new InitialContext().lookup(jndiName);
    }
}

@Resource

This is more of a general purpose annotation used to declare a required resource and is applicable to methods, fields as well as a class. Please note that the usage of this annotation is not restricted to EJBs alone - all Managed Beans (which is almost every bean out there) can leverage its capabilities

Just like @EJB, @Resource also has additional elements: name, type, mappedName, lookup, description, authenticationType, shareable

It can be used to inject a number of types like

  • Java primitives (and their wrapper versions)
  • JMS resources (connection factories, destinations)
  • User Transactions
  • Web service references
  • JDBC data sources
  • Timer service
  • EJB context etc.
  • Concurrency utilities components like Managed Service executors etc.
package ejbap.di_and_ri;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;

@Singleton
@Startup
public class ResourcefulBean {

    @Resource
    ConnectionFactory jmsCF;
    @Resource
    Destination jmsDestination;       
    @Resource
    TimerService ejbTs;    

    @PostConstruct
    public void setUp(){
        ejbTs.createSingleActionTimer(10000, new TimerConfig());
    }        

    @Timeout
    public void onTimeout(){
        jmsCF.createContext().createProducer().send(jmsDestination, "a new message triggered by timer");
    }
}

Class vs. method/field usage

It is important to understand the behaviour respective to these usage scenarios

  • the class usage means that the dependent resource will be accessed at runtime
  • field/method usage implies that the resource injection will take place during application initialization

@Resources

@Resources is to @Resource what @Schedules is to @Schedule - it provides a way to declare multiple dependent resources. This is because of the fact that prior to Java SE 8, multiple annotations on an element were not possible. I am sure things will be refactored in Java EE 8 which will (most probably) have Java 8 as a mandatory requirement

@Resources can only be applied on a class

package ejbap.di_and_ri;

import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.ejb.Stateless;
import javax.enterprise.concurrent.ManagedExecutorService;
import javax.sql.DataSource;

@Stateless
@Resources({
@Resource(lookup="java:comp/DefaultManagedExecutorService", 
        type = ManagedExecutorService.class),
@Resource(lookup = "java:comp/DefaultDataSource" , 
        type = DataSource.class)
})
public class MultipleResources {

}

Both @Resource and @Resources, belong to the Common Annotations specification (JSR 250)

EJB DI using CDI...

This section will provide a brief note on how EJB injection is also possible using CDI (a specification added to the Java EE 6 Platform).

EJB, CDI, their differences, similarities and relationships are topics which are not covered in depth

@Inject

This CDI annotation is a powerful, general purpose and type safe injection construct. During container bootstrap, CDI container makes use of a process called Type Safe Resolution in order to validate whether or not there are beans which satisfy the injection points (else the application deployment is aborted). The CDI specification also offers other components like Qualifiers (default & custom), Alternatives etc. which complement @Inject

@EJB & @Inject: what's the difference ?

Simply put, @Inject can be leveraged to inject type which qualifies as a CDI bean while @EJB (as discussed previously) can be used for dependency injection of Session beans only. Although, @Resource can be thought of as a more general purpose DI mechanism, CDI is more powerful and in fact works very well in tandem with @Resource (via CDI Producers)

Valid CDI scopes for Session (EJB) beans

CDI enriches the EJB specification (Session beans to be specific) by providing contextual life cycle management. Session beans are not ‘contextual’ instances in general. Here are the valid permutations and combinations of EJB session beans and corresponding CDI scopes (Application, Session or Request)

  • Stateless beans can only belong to the @Dependent scope i.e. you can either choose to use the @Dependent pseudo-scope explicitly or just flow with the @Stateless annotation in which case the CDI container will pretty much use @Dependent by default (convention).
  • With Singleton beans, @ApplicationScoped is the only valid CDI scope (@Dependent is the default in case you do not use any other explicit CDI scope)
  • Stateful EJBs can have any scope – no restrictions whatsoever!

Injecting Session beans

Unless you are using refined versions of @EJB, @Inject can pretty much be a drop in replacement for injecting session beans and should work seamlessly

Injection in Session beans

Support for @Inject within session beans is supported by the specification. The basic CDI rules apply here as well

Let's move on

... and explore the different views which session beans expose to their clients.

results matching ""

    No results matching ""