2011-12-22 31 views
10

Tôi đang lập kế hoạch sử dụng EJBContext để chuyển một số thuộc tính xung quanh từ tầng ứng dụng (cụ thể, một bean điều khiển tin nhắn) đến cuộc gọi lại vòng đời kiên trì không thể trực tiếp được đưa vào hoặc truyền tham số (trình nghe phiên trong EclipseLink, gọi lại vòng đời thực thể, v.v. .), và gọi lại đó là nhận được EJBContext qua JNDI.Sử dụng EJBCtext getContextData - điều này có an toàn không?

Điều này có vẻ hoạt động nhưng có bất kỳ dấu hiệu bị ẩn nào, như độ an toàn của chủ đề hoặc tuổi thọ đối tượng mà tôi đang thiếu không? (Giả sử giá trị tài sản được thông qua là bất di bất dịch như String hay Long.)

mẫu đậu đang

@MessageDriven 
public class MDB implements MessageListener { 
    private @Resource MessageDrivenContext context; 

    public void onMessage(Message m) { 
     context.getContextData().put("property", "value"); 
    } 
} 

Sau đó gọi lại mà tiêu thụ các EJBContext

public void callback() { 
    InitialContext ic = new InitialContext(); 
    EJBContext context = (EJBContext) ic.lookup("java:comp/EJBContext"); 
    String value = (String) context.getContextData().get("property"); 
} 

Những gì tôi đang tự hỏi là, tôi có thể chắc chắn rằng nội dung bản đồ contextData chỉ hiển thị với lời gọi/chuỗi hiện tại không? Nói cách khác, nếu hai luồng đang chạy đồng thời phương thức callback và cả hai đều tra cứu một số EJBContext từ JNDI, chúng thực sự nhận được nội dung bản đồ khác nhau contextData?

Và, làm thế nào để thực sự làm việc - là EJBContext trả về từ tra cứu JNDI thực sự là một đối tượng bao quanh một cấu trúc giống như ThreadLocal cuối cùng?

Trả lời

8

Tôi nghĩ rằng nói chung các hợp đồng của phương pháp này là cho phép các giao tiếp giữa interceptors + ngữ cảnh webservice và bean. Vì vậy, ngữ cảnh sẽ có sẵn cho tất cả mã, miễn là không có ngữ cảnh yêu cầu mới nào được tạo. Vì vậy, nó nên được hoàn toàn thread-an toàn.

Mục 12,6 của EJB 3.1 spec nói như sau:

Đối tượng InvocationContext cung cấp siêu dữ liệu cho phép phương pháp đánh chặn để kiểm soát hành vi của chuỗi sự thỉnh nguyện. Dữ liệu theo ngữ cảnh không thể chia sẻ trên phương thức kinh doanh riêng biệt các sự kiện gọi lại hoặc gọi lại vòng đời. Nếu chặn được gọi như là kết quả của sự thỉnh nguyện trên một thiết bị đầu cuối dịch vụ web, bản đồ trả về bởi getContextData sẽ là JAX-WS MessageContext

Hơn nữa, phương pháp getContextData được mô tả trong 4.3.3:

Phương thức getContextData cho phép phương thức nghiệp vụ, phương thức gọi lại vòng đời hoặc phương thức hết thời gian để truy xuất bất kỳ ngữ cảnh chặn/webservices nào được kết hợp với lời gọi của nó.

Xét về thực tế triển khai, JBoss AS nào sau đây:

public Map<String, Object> getContextData() { 
    return CurrentInvocationContext.get().getContextData(); 
} 

Trường hợp CurrentInvocationContext sử dụng một ngăn xếp dựa trên một thread-local linked list để bật và đẩy bối cảnh gọi hiện tại.

Xem org.jboss.ejb3.context.CurrentInvocationContext. Ngữ cảnh yêu cầu chỉ lười biếng tạo ra một đơn giản HashMap, như được thực hiện trong org.jboss.ejb3.interceptor.InvocationContextImpl

Thủy tinh làm điều tương tự. Nó cũng gets an invocation và thực hiện điều này from an invocation manager, cũng sử dụng ngăn xếp dựa trên thread-local array list để bật và đẩy lại các ngữ cảnh yêu cầu này.

Các javadoc cho việc thực hiện GlassFish là đặc biệt thú vị ở đây:

này TLS cửa hàng biến một ArrayList. ArrayList chứa Các đối tượng ComponentInvocation đại diện cho chồng các lời gọi trên chủ đề này. Truy cập vào ArrayList không cần phải được đồng bộ vì mỗi luồng có ArrayList riêng của nó.

Cũng giống như trong JBoss AS, GlassFish quá lười biếng tạo ra một đơn giản HashMap, trong trường hợp này là com.sun.ejb.EjbInvocation. Thú vị trong trường hợp GlassFish là kết nối webservice dễ phát hiện hơn trong nguồn.

9

Tôi không thể giúp bạn trực tiếp với các câu hỏi của bạn về EJBContext, vì phương pháp getContextData đã được thêm vào JEE6 vẫn chưa có nhiều tài liệu về nó.

Tuy nhiên, có một cách khác để chuyển dữ liệu theo ngữ cảnh giữa EJB, bộ chặn và cuộc gọi lại vòng đời bằng cách sử dụng TransactionSynchronizationRegistry. Khái niệm và mã mẫu có thể được tìm thấy trong số blog post by Adam Bien này.

javax.transaction.TransactionSynchronizationRegistry giữ cấu trúc giống như bản đồ và có thể được sử dụng để chuyển trạng thái bên trong giao dịch. Nó hoạt động hoàn hảo kể từ J2EE cũ 1.4 ngày và không phụ thuộc vào luồng.

Vì Trình chặn được thực hiện trong cùng một giao dịch với ServiceFacade, trạng thái có thể được đặt trong phương thức @AroundInvoke. Các TransactionSynchronizationRegistry (TSR) có thể được tiêm trực tiếp vào một Interceptor.

Ví dụ có sử dụng @Resource tiêm để có được những TransactionSynchronizationRegistry, nhưng nó cũng có thể được nhìn lên từ InitialContext như thế này:

public static TransactionSynchronizationRegistry lookupTransactionSynchronizationRegistry() throws NamingException { 
    InitialContext ic = new InitialContext(); 
    return (TransactionSynchronizationRegistry)ic.lookup("java:comp/TransactionSynchronizationRegistry"); 
} 
+1

Đề xuất tốt. Mẫu tôi đang sử dụng cho 'EJBContext' gần như giống hệt nhau - tiêm' @ Resource' ở một nơi, đặt các đối tượng vào bản đồ, và sau đó tìm kiếm trong JNDI ở một nơi khác. Vì vậy, câu hỏi đặt ra là liệu đối tượng 'EJBContext' cũng không độc lập như' TransactionSynchronizationRegistry' – wrschneider

+1

TransactionSynchronizationRegistry có một giới hạn: nó luôn cần giao dịch, nhưng trong một số trường hợp là cần thiết để truyền thông tin mà không cần giao dịch – obe6

Các vấn đề liên quan