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 Bean 已完整整合入 Java EE 環境中。Web Bean 可存取 Java EE 資源以及 JPA persistence context。它們可能會被使用於 JSF 以及 JSP 網頁中的 Unified EL 表示式中。它們也可被注入一些物件中,例如 Servlets 以及訊息導向的 Bean 中(非 Web Beans)。

所有基本與企業的 Web Bean 都能透過 @Resource@EJB 以及 @PersistenceContext 來有效利用 Java 依賴注入(dependency injection)。我們早已見過了這方面的範例,不過當時我們並未詳細討論到:

@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 Bean 也都支援 Java EE @PostConstruct@PreDestroy 的 callback。@PostConstruct 這個 method 會在所有注入被進行後才會被調用。

在此有項需要注意的限制:基本的 Web Bean 並不支援 @PersistenceContext(type=EXTENDED)

在 Java EE 6 中透過 Servlet 來使用 Web Bean 相當地簡單。只要使用 Web Bean 欄位或是 initializer method 注入來注入 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 Bean 的客戶端 proxy 能為目前的請求以及 HTTP session 處理由 Servlet 至 CredentialsLogin 的正確事例的 routing method 調用。

Web Bean 注入適用於所有 EJB,儘管它們不是由 Web Bean 管理員所控制(比方說若它們是透過直接的 JNDI 搜尋或是透過使用 @EJB 來被取得的情況下)。特別是,您可在訊息導向的 Bean 中使用 Web Bean 注入,不過這些 Bean 並不被視為是 Web Bean 因為您無法注入它們。

針對於訊息導向的 Bean,您甚至可使用 Web Bean 攔截器綁定。

@Transactional @MessageDriven

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

因此,在 Web Bean 環境下,取得訊息是相當地簡單的。不過請注意,當訊息提交至一個訊息導向的 Bean 時,不會有可用的 session 或是對話 context。只有 @RequestScoped@ApplicationScoped Web Bean 可使用。

透過使用 Web Bean 來傳送訊息也相當地簡單。

基於需要處理許多不同的物件,因此透過使用 JMS 來傳送訊息可能會相當複雜。針對於 queue,我們有 QueueQueueConnectionFactoryQueueConnectionQueueSession 以及 QueueSender。針對於 topic 我們有 TopicTopicConnectionFactoryTopicConnectionTopicSession 以及 TopicPublisher。針對於各個這些物件,我們都需要去顧及它們自己各別的生命週期和執行緒模型(threading model)。

Web Bean 會全部為我們處理。我們只需要在 web-beans.xml 中宣告 queue 或是 topic,指定關聯的綁定類型和連接因數(connection factory)。


<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 注入 QueueQueueConnectionQueueSessionQueueSender,或是為 topic 注入 TopicTopicConnectionTopicSession 或是 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 Bean 不會定義任何特殊的建置 archive。您可將 Web Bean 封裝在 JARs、EJB-JARs 或是 WARs — 中,應用程式 classpath 中的任何建置位置上。不過,各個包含著 Web Bean 的 archive 在 META-INF 或是 WEB-INF 目錄中都必須包含著一個稱為 web-beans.xml 的檔案。該檔案能是空的。建置於一個沒有 web-beans.xml 檔案的 archive 中的 Web Bean 將無法使用於應用程式中。

對於 Java SE 的執行來說,Web Bean 可被建置於任何位置上,同時 EJB 亦可被建置來讓可崁入的 EJB Lite container 執行。再次強調,各個位置都必須包含著一個 web-beans.xml 檔案。