SeamFramework.orgCommunity Documentation

第 13 章 Java EE整合

13.1. 将Java EE资源注入到一个Web Bean中
13.2. 从Servlet调用一个Web Bean
13.3. 从消息驱动Bean中调用一个Web Bean
13.4. JMS端点
13.5. 打包和部署

Web Beans被完全地整合进了Java EE环境里。Web Beans 能够访问Java EE资源和JPA持久化上下文。它们可以在JSF和JSP页面中的统一表达式语言使用。它们甚至可以被注入到一些对象中,例如Servlet和消息驱动Bean,而这些对象都不是Web Bean。

所有简单的和企业的Web Beans都可以通过@Resource, @EJB@PersistenceContext来使用Java EE的依赖注入。我们已经看过很多例子了,虽然我们没有在这上面耗费精力:

@Transactional @Interceptor

public class TransactionInterceptor {
    @Resource Transaction transaction;
    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
    
}
@SessionScoped

public class Login {
    @Current Credentials credentials;
    @PersistenceContext EntityManager userDatabase;
    
    ...
}

所有的简单的和企业的Web Beans都支持Java EE的@PostConstruct@PreDestroy回调。@PostConstruct方法在所有的 注入完成后被调用。

这里需要注意的一个限制是:简单的Web Beans不支持 @PersistenceContext(type=EXTENDED)

在Java EE 6中,从一个Servlet中调用一个Web Bean非常容易,只须使用Web Beans域注入一个Web Bean或者将初始方法注入即可。

public class Login extends HttpServlet {


    @Current Credentials credentials;
    @Current Login login;
    @Override
    public void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        credentials.setUsername( request.getAttribute("username") ):
        credentials.setPassword( request.getAttribute("password") ):
        login.login();
        if ( login.isLoggedIn() ) {
            response.sendRedirect("/home.jsp");
        }
        else {
            response.sendRedirect("/loginError.jsp");
        }
    }
            
}

Web Beans客户端代理将Servlet中的方法调用路由到当前请求和HTTP会话中相应的CredentialsLogin 实例。

Web Beans注入可以应用于所有的EJB,甚至这些EJB不在Web Bean管理器的控制之下也可以(如果它们可以直接从JNDI查找或者使用@EJB注入)。消息驱动Bean不能成为Web Beans,因为你无法注入它们,但你仍然可以将Web Beans注入到消息驱动Bean中。

你甚至可以将Web Beans拦截器绑定到消息驱动Bean上。

@Transactional @MessageDriven

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

这样,在一个Web Beans环境中接受消息就相当简单了。但是需要注意的是,当一个消息发送到一个消息驱动Bean的时候,此时没有会话,我们无法获得对话上下文。我们只能获得 @RequestScoped@ApplicationScoped 注释的Web Beans。

使用Web Beans发送消息也相当简单。

使用JMS发送消息有点复杂,因为你需要处理很多不同的对象。对于队列(Queue),我们有Queue, QueueConnectionFactory, QueueConnection, QueueSessionQueueSender。对于主题(Topic)有Topic, TopicConnectionFactory, TopicConnection, TopicSessionTopicPublisher。这些对象每个都有自己的生命周期和线程模型,我们都需要考虑这些问题。

Web Beans为我们处理所有这些问题。我们只须在 web-beans.xml声明队列或者主题,指定一个关联的绑定类型和连接工厂即可。


<Queue>
    <destination
>java:comp/env/jms/OrderQueue</destination>
    <connectionFactory
>java:comp/env/jms/QueueConnectionFactory</connectionFactory>
    <myapp:OrderProcessor/>    
</Queue
>

<Topic>
    <destination
>java:comp/env/jms/StockPrices</destination>
    <connectionFactory
>java:comp/env/jms/TopicConnectionFactory</connectionFactory>
    <myapp:StockPrices/>    
</Topic
>

现在,对于队列,我们只须注入 Queue, QueueConnection, QueueSession 或者 QueueSender;对于主题,我们只须注入Topic, TopicConnection, TopicSession 或者 TopicPublisher

@OrderProcessor QueueSender orderSender;

@OrderProcessor QueueSession orderSession;
public void sendMessage() {
    MapMessage msg = orderSession.createMapMessage();
    ...
    orderSender.send(msg);
}
@StockPrices TopicPublisher pricePublisher;

@StockPrices TopicSession priceSession;
public void sendMessage(String price) {
    pricePublisher.send( priceSession.createTextMessage(price) );
}

被注入的JMS对象的生命周期完全由Web Bean管理器控制。

Web Beans并没有指定特殊的部署包。你可以以JAR, EJB-JAR或者WAR—形式将Web Beans打包在任何应用类路径中的部署位置上。然而,每个包含Web Beans的包必须在META-INF 或者 WEB-INF目录下包含一个名为 web-beans.xml的配置文件。这个文件可以是空的。没有web-beans.xml 配置文件,应用将无法使用Web Beans。

对于Java SE,Web Beans可以被部署在由嵌入式EJB轻量容器支持的EJB中的任何位置。同样,该位置必须包含 web-beans.xml 配置文件。