SeamFramework.orgCommunity Documentation

Capítulo 15. Integração com o Java EE

15.1. Beans embutidos
15.2. Injetando recursos Java EE em um bean
15.3. Invocando um bean a partir de um Servlet
15.4. Invocando um bean a partir de um message-driven bean
15.5. Endpoints JMS
15.6. Empacotamento e implantação

CDI está plenamente integrada ao ambiente Java EE. Os beans possuem acesso aos recursos Java EE e aos contextos de persistência JPA. Eles podem ser utilizados em expressões EL Unificadas (Unified EL) e em páginas JSF e JSP. Podem até ser injetados em outros componentes da plataforma, tais como servlets e message-driven Beans, que não são bens por si só.

No ambiente Java EE, o contêiner fornece os seguintes beans embutidos, todos com o qualificador @Default:

Nota

A especificação CDI não requer que os objetos de contexto de servlet HttpServletRequest, HttpSession e ServletContext sejam expostos como beans injetáveis. Se você realmente quer ser capaz de injetar estes objetos, é fácil criar uma extensão portável para expô-los como beans. No entanto, recomendamos que o acesso direto a estes objetos estejam limitados a servlets, servlet filters e servlet event listeners, onde podem ser obtidos da maneira usual, tal como definido pela especificação Java Servlets. O objeto FacesContext também não é injetável. Você pode obtê-lo chamando FacesContext.getCurrentInstance().

Nota

Oh, você realmente quer injetar o FacesContext? Tudo bem então, tente este método produtor:

class FacesContextProducer {

   @Produces @RequestScoped FacesContext getFacesContext() {
      return FacesContext.getCurrentInstance();
   }
}

Todos os beans gerenciados poder tirar vantagem da injeção de componentes do ambiente Java EE usando @Resource, @EJB, @PersistenceContext, @PeristenceUnit e @WebServiceRef. Nós já vimos uma porção de exemplos disto, embora não tenhamos prestado muita atenção no momento:

@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;
    ...
}

As chamadas Java EE @PostConstruct e @PreDestroy também são suportadas em todos os beans controlados. O método anotado com @PostConstruct é invocado após todas injeções serem realizadas.

Certamente, aconselhamos que a injeção de componentes do ambiente seja usada para definir recursos CDI, e que injeção typesafe seja usada no código da aplicação.

É fácil usar um bean a partir de uma servlet no Java EE 6. Simplesmente injete o bean usando um campo ou injeção por um método inicializador.

public class Login 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");
      }
   }
            
}

Uma vez que instâncias de servlets são compartilhadas através de todas threads entrantes, o proxy cliente cuida do encaminhamento das invocações dos métodos do servlet para as instâncias corretas de Credentials e Login para a requisição e sessão HTTP atuais.

A injeção CDI se aplica a todos EJBs, mesmo quando eles não são beans gerenciados. Em especial, você pode usar injeção CDI em message-driven beans, os quais são por natureza objetos não contextuais.

Você ainda pode usar bindings de interceptação da CDI em message-driven Beans.

@Transactional @MessageDriven

public class ProcessOrder implements MessageListener {
   @Inject Inventory inventory;
   @PersistenceContext EntityManager em;
   public void onMessage(Message message) {
      ...
   }
}

Note que existe nenhuma sessão ou contexto de conversação disponível quando uma mensagem é entregue a um message-driven bean. Apenas benas @RequestScoped e @ApplicationScoped estão disponíveis.

Mas como que beans enviam mensagens JMS?

O envio de mensagens usando JMS pode ser bastante complexo, devido à quantidade de objetos diferentes que precisamos utilizar. Para filas, temos Queue, QueueConnectionFactory, QueueConnection, QueueSession e QueueSender. Para os tópicos, temos Topic, TopicConnectionFactory, TopicConnection, TopicSession e TopicPublisher. Cada um desses objetos tem seu próprio ciclo de vida e modelo de threads, com que temos de nos preocupar.

Você pode usar campos e métodos produtores para preparar todos estes recursos para injeção em um bean:

public class OrderResources {

   @Resource(name="jms/ConnectionFactory")
   private ConnectionFactory connectionFactory;
  
   @Resource(name="jms/OrderQueue")
   private Queue orderQueue;
  
   @Produces @OrderConnection
   public Connection createOrderConnection() throws JMSException {
    return connectionFactory.createConnection();
   }
  
   public void closeOrderConnection(@Disposes @OrderConnection Connection connection)
         throws JMSException {
      connection.close();
   }
  
   @Produces @OrderSession
   public Session createOrderSession(@OrderConnection Connection connection)
         throws JMSException {
      return connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
   }
  
   public void closeOrderSession(@Disposes @OrderSession Session session)
         throws JMSException {
      session.close();
   }
  
   @Produces @OrderMessageProducer
   public MessageProducer createOrderMessageProducer(@OrderSession Session session)
         throws JMSException {
      return session.createProducer(orderQueue);
   }
  
   public void closeOrderMessageProducer(@Disposes @OrderMessageProducer MessageProducer producer)
         throws JMSException {
      producer.close();
   }
}

Neste exemplo, podemos injetar apenas MessageProducer, Connection ou QueueSession:

@Inject Order order;

@Inject @OrderMessageProducer MessageProducer producer;
@Inject @OrderSession QueueSession orderSession;
public void sendMessage() {
   MapMessage msg = orderSession.createMapMessage();
   msg.setLong("orderId", order.getId());
   ...
   producer.send(msg);
}

O ciclo de vida dos objetos JMS injetados são completamente controlados pelo contêiner.

CDI não define qualquer arquivo de implantação especial. Você pode empacotar beans em jars, ejb jars ou wars—qualquer local no classpath da aplicação em implantação. Entretanto, o arquivo deve ser um "arquivo de beans". Isto significa que arquivos contendo beans deve incluir um arquivo nomeado como beans.xml no diretório META-INF do classpath ou no diretório WEB-INF (para arquivos war). O arquivo pode ser vazio. Os beans implantados em arquivos que não possuam um beans.xml não estarão disponíveis para uso na aplicação.

Em um contêiner EJB embutido, os beans podem ser implantados em qualquer local em que EJBs podem ser implantados. Novamente, cada local deve conter um arquivo beans.xml.