10/09/2007

Why we need type-level injections in JavaEE?

As I wrote in the previous post, JavaEE type-level injection is more verbose than field and setter injections. So why don't we just all use the simple field or setter injections? Well, there are some times a type-level injection is more appropriate

1. You want to lazily initialize a field such as a data source or bean. Having the container to initialize a field via field injection or setter injection has its overhead. With type-level injection, you have the resource and EJB reference fully configured without descriptors, but defer the actual initialization. Whenever you need the resource, just look it up.

Type-level injection also works well if you want to reference the injected resource in some non-component utility classes that are in the same naming context. Since only JavaEE component classes can take injections, you can't inject into POJO utility classes. For example, you can

@Resource(type=javax.sql.DataSource.class, 
name="jdbc/defaultDataSource,
mappedName="jdbc/__default")

public class FooServlet extends HttpServlet {
//the service method, or doGet, doPost, etc, references ServletUtil
}

public class ServletUtil {
private void help() throws ServletException {
//This is how to use the resource injected at type-level in FooServlet
Connection con = null;
try {
InitialContext ic = new InitialContext();
DataSource ds =
(DataSource) ic.lookup("java:comp/env/jdbc/defaultDataSource");
con = ds.getConnection();
} catch (NamingException ex) {
throw new ServletException(ex);
} catch (SQLException ex) {
throw new ServletException(ex);
} finally {
//close connection here
}
}
The above example will also if we instead use field or setter injection. But the instance filed in FooServlet class that takes the injection may not be used at all. Another approach is to pass the data source reference injected into FooServlet as method parameters to ServletHelper. But it pollutes the API. It appears more natural, at least to me, to use type-level injection in this case.

2. You want to restrict the scope or sharing of the variable that references the resource. Field and setter injections both use instance variables, which are accessible to all methods and all threads of the current component instance. Instance variables represent shared states. With type-level injections, you typically assign the resource to a local variable and thus is thread-safe.

This is the reason why you shouldn't inject an EJB 3 stateful session bean into a servlet class variable. In so doing, this stateful bean variable will be shared by all request-processing threads running inside the servlet's service method. Servlet is stateless, so it should not keep state (the stateful session bean reference).

No comments: