Java EE integration
CDI is fully integrated into the Java EE environment. Beans have access to Java EE resources and JPA persistence contexts. They may be used in Unified EL expressions in JSF and JSP pages. They may even be injected into other platform components, such as servlets and message-driven Beans, which are not beans themselves.
Built-in beans
In the Java EE environment, the container provides the following
built-in beans, all with the qualifier @Default
:
-
the current JTA
UserTransaction
, -
a
Principal
representing the current caller identity, -
the default Bean Validation
ValidationFactory
, -
a
Validator
for the defaultValidationFactory
, -
HttpServletRequest
,HttpSession
andServletContext
Note
|
The
|
Injecting Java EE resources into a bean
All managed beans may take advantage of Java EE component environment
injection using @Resource
, @EJB
, @PersistenceContext
,
@PersistenceUnit
and @WebServiceRef
. We’ve already seen a couple of
examples of this, though we didn’t pay much attention at the time:
@Transactional @Interceptor
public class TransactionInterceptor {
@Resource UserTransaction transaction;
@AroundInvoke public Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}
@SessionScoped
public class Login implements Serializable {
@Inject Credentials credentials;
@PersistenceContext EntityManager userDatabase;
...
}
The Java EE @PostConstruct
and @PreDestroy
callbacks are also
supported for all managed beans. The @PostConstruct
method is called
after all injection has been performed.
Of course, we advise that component environment injection be used to define CDI resources, and that typesafe injection be used in application code.
Calling a bean from a servlet
It’s easy to use a bean from a servlet in Java EE. Simply inject the bean using field or initializer method injection.
public class LoginServlet extends HttpServlet {
@Inject Credentials credentials;
@Inject Login login;
@Override
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
credentials.setUsername(request.getParameter("username")):
credentials.setPassword(request.getParameter("password")):
login.login();
if ( login.isLoggedIn() ) {
response.sendRedirect("/home.jsp");
}
else {
response.sendRedirect("/loginError.jsp");
}
}
}
Since instances of servlets are shared across all incoming threads, the
bean client proxy takes care of routing method invocations from the
servlet to the correct instances of Credentials
and Login
for the
current request and HTTP session.
Calling a bean from a message-driven bean
CDI injection applies to all EJBs, even when they aren’t CDI beans. In particular, you can use CDI injection in message-driven beans, which are by nature not contextual objects.
You can even use interceptor bindings for message-driven Beans.
@Transactional @MessageDriven
public class ProcessOrder implements MessageListener {
@Inject Inventory inventory;
@PersistenceContext EntityManager em;
public void onMessage(Message message) {
...
}
}
Please note that there is no session or conversation context available
when a message is delivered to a message-driven bean. Only
@RequestScoped
and @ApplicationScoped
beans are available.
But how about beans which send JMS messages?
JMS endpoints
Sending messages using JMS can be quite complex, because of the number
of different objects you need to deal with. For queues we have Queue
,
QueueConnectionFactory
, QueueConnection
, QueueSession
and
QueueSender
. For topics we have Topic
, TopicConnectionFactory
,
TopicConnection
, TopicSession
and TopicPublisher
. Each of these
objects has its own lifecycle and threading model that we need to worry
about.
You can use producer fields and methods to prepare all of these resources for injection into a bean:
import javax.jms.ConnectionFactory;
import javax.jms.Queue;
public class OrderResources {
@Resource(name="jms/ConnectionFactory")
private ConnectionFactory connectionFactory;
@Resource(name="jms/OrderQueue")
private Queue orderQueue;
@Produces @Order
public Connection createOrderConnection() throws JMSException {
return connectionFactory.createConnection();
}
public void closeOrderConnection(@Disposes @Order Connection connection)
throws JMSException {
connection.close();
}
@Produces @Order
public Session createOrderSession(@Order Connection connection)
throws JMSException {
return connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
}
public void closeOrderSession(@Disposes @Order Session session)
throws JMSException {
session.close();
}
@Produces @Order
public MessageProducer createOrderMessageProducer(@Order Session session)
throws JMSException {
return session.createProducer(orderQueue);
}
public void closeOrderMessageProducer(@Disposes @Order MessageProducer producer)
throws JMSException {
producer.close();
}
}
In this example, we can just inject the prepared MessageProducer
,
Connection
or QueueSession
:
@Inject Order order;
@Inject @Order MessageProducer producer;
@Inject @Order Session orderSession;
public void sendMessage() {
MapMessage msg = orderSession.createMapMessage();
msg.setLong("orderId", order.getId());
...
producer.send(msg);
}
The lifecycle of the injected JMS objects is completely controlled by the container.
Packaging and deployment
CDI doesn’t define any special deployment archive. You can package CDI beans in JARs, EJB JARs or WARs—any deployment location in the application classpath. However, the archive must be a "bean archive".
Unlike CDI 1.0, the CDI 1.1 specification recognizes two types of bean archives. The type determines the way the container discovers CDI beans in the archive.
Note
|
CDI 1.1 makes use of a new XSD file for beans.xml descriptor: http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd |
Explicit bean archive
An explicit bean archive is an archive which contains a beans.xml
file:
-
with a version number of 1.1 (or later), with the bean-discovery-mode of
all
, or, -
like in CDI 1.0 – with no version number, or, that is an empty file.
It behaves just like a CDI 1.0 bean archive – i.e. Weld discovers each Java class, interface or enum in such an archive.
Note
|
The
You should never place a |
Trimmed bean archive
Optionally beans.xml
file in explicit bean archive can include simple trim
element. This trimmed bean archive means that ProcessAnnotatedType
event is
fired for every AnnotatedType
, but only types which are annotated with a
bean defining annotation or any scope annotation will become beans.
Implicit bean archive
An implicit bean archive is an archive which contains one or more bean
classes with a bean defining annotation, or one or more session beans.
It can also contain a beans.xml
file with a version number of 1.1 (or
later), with the bean-discovery-mode of annotated
. Weld only discovers
Java classes with a bean defining annotation within an implicit bean
archive.
Note
|
The set of bean defining annotations contains:
However, |
Which archive is not a bean archive
Although quite obvious, let’s sum it up:
-
an archive which contains neither a
beans.xml
file nor any bean class with a bean defining annotation, -
an archive which contains a
beans.xml
file with the bean-discovery-mode ofnone
.
Actually, there is one more special rule (designed to retain backward compatibility): an archive which contains a portable extension and no beans.xml
is not a bean archive either.
However, this is not a very common use case.
Note
|
For compatibility with CDI 1.0, each Java EE product (WildFly,
GlassFish, etc.) must contain an option to cause an archive to be
ignored by the container when no beans.xml is present. Consult
specific Java EE product documentation to learn more about such option.
|
Embeddable EJB container
In an embeddable EJB container, beans may be deployed in any location in which EJBs may be deployed.