2010-05-04 35 views
7

Một ngày trước, đơn của tôi là một EAR, chứa một WAR, một EJB JAR và một vài tệp JAR tiện ích. Tôi đã có một lớp POJO singleton thuộc một trong các tập tin tiện ích, nó làm việc, và tất cả là tốt với thế giới:Làm cách nào để viết một Java EE/EJB Singleton?

EAR 
|--- WAR 
|--- EJB JAR 
|--- Util 1 JAR 
|--- Util 2 JAR 
|--- etc. 

Sau đó, tôi đã tạo ra một WAR thứ hai và phát hiện ra (cách cứng) mà mỗi WAR có của nó ClassLoader riêng, vì vậy mỗi WAR thấy một singleton khác nhau, và mọi thứ bị phá vỡ từ đó. Đây không phải là quá tốt.

EAR 
|--- WAR 1 
|--- WAR 2 
|--- EJB JAR 
|--- Util 1 JAR 
|--- Util 2 JAR 
|--- etc. 

Vì vậy, tôi đang tìm cách tạo đối tượng đơn lẻ Java sẽ hoạt động trên các WAR (qua Lớp nạp)? Chú thích EJB @Singleton có vẻ khá hứa hẹn cho đến khi tôi phát hiện ra rằng JBoss 5.1 dường như không hỗ trợ chú thích đó (được thêm vào như là một phần của EJB 3.1). Tôi đã bỏ lỡ điều gì đó - tôi có thể sử dụng @Singleton với JBoss 5.1 không? Nâng cấp lên JBoss AS 6 không phải là một tùy chọn ngay bây giờ.

Cách khác, tôi rất vui khi không phải sử dụng EJB để triển khai đĩa đơn của mình. Tôi có thể làm gì khác để giải quyết vấn đề này? Về cơ bản, tôi cần một hook * bán rộng ứng dụng vào một bó toàn bộ các đối tượng khác, giống như các dữ liệu được lưu trữ khác nhau và thông tin cấu hình ứng dụng. Như một phương sách cuối cùng, tôi đã xem xét việc sáp nhập hai WAR của tôi thành một, nhưng điều đó sẽ khá khủng khiếp.

* Ý nghĩa: có sẵn về cơ bản ở bất kỳ đâu trên một lớp nhất định; bây giờ, chủ yếu là trong WAR của tôi - xem và điều khiển (trong một ý nghĩa lỏng lẻo).

Chỉnh sửa: Tôi thực sự nên gọi nó là Java EE thay vì J2EE, phải không?


Chỉnh sửa 2: Rất cám ơn một lần nữa để @Yishai cho tất cả sự giúp đỡ. Sau khi một số thử nghiệm và lỗi có vẻ như tôi đã tìm ra cách sử dụng một ClassLoader duy nhất trên các WAR dưới JBoss 5. Tôi đang chi tiết điều này dưới đây vì lợi ích của riêng tôi, và hy vọng những người khác cũng sẽ thấy điều này hữu ích.

N.B. điều này khá khác với việc thực hiện điều này dưới JBoss 4 (xem câu trả lời của Yishai hoặc các liên kết của tôi bên dưới).

Thay vì viết một jboss-web.xml cho mỗi WAR, và một jboss.xml cho tai EJB-JAR, đặt một tập tin jboss-classloading.xml trong mỗi WAR, trong cùng một vị trí như DD (web.xml). Nội dung của jboss-classloading.xml nên là:

<?xml version="1.0" encoding="UTF-8"?> 
<classloading 
    xmlns="urn:jboss:classloading:1.0" 
    name="mywar.war" 
    domain="DefaultDomain" 
    parent-domain="Ignored" 
    export-all="NON_EMPTY" 
    import-all="true"> 
</classloading> 

này xuất phát từ JBoss CW here, trong khi những gì (tôi nghĩ) làm việc cho JBoss 4.x được mô tả here. Xem thêm thông tin chung về JBoss classload (ing/ERS):

Như tốt nhất mà tôi có thể nói, các JBoss docs wiki cộng đồng đang khá thiếu cho JBoss 5 so với JBoss 4.

+0

@Bears, re: the edit: Chỉ khi bạn làm việc trong bộ phận tiếp thị của Oracle. – Yishai

Trả lời

11

Mặc dù spec EJB3.1 giới thiệu singleton và các phiên bản của JBoss không hỗ trợ nó, bạn có thể sử dụng chú thích JBoss @Service để tạo ra một singleton. Hướng dẫn here. Ngoài ra, có vẻ như bạn đã cấu hình JBoss để cô lập các jars và cuộc chiến tranh của bạn với nhau. Bạn không phải làm vậy. Bạn có thể xem thẻ loader-repository trong các tệp xml cụ thể của jboss để toàn bộ tai của bạn chia sẻ một trình nạp lớp (hoặc có lẽ ít nhất hai cuộc chiến chia sẻ một trình nạp lớp).

Tất cả những gì được nói, tôi đồng ý với @duffymo, rằng một singleton chia sẻ trạng thái giữa hai cuộc chiến tranh là một ý tưởng rằng bạn nên đi bộ, nếu không chạy trốn.

Chỉnh sửa: Về người độc thân, tôi khuyên bạn nên xem các câu hỏi như this one (cũng có số dư tốt trong nhận xét). Ý tưởng của việc có một đối tượng giữ trạng thái lưu trữ trong và chính nó là ok, đặc biệt là với EJB3, nơi bạn có thể tiêm trạng thái của bạn thay vì tham chiếu tĩnh (nếu bạn sử dụng chú thích @Service, thì bạn muốn @Depends JBoss). chú thích cụ thể). Điều đó đang được nói, nếu bạn đang sử dụng một singleton "thích hợp" ở đây, thì tôi sẽ cho rằng vấn đề duy nhất của bạn với thực tế là các WAR của bạn có hai trình nạp lớp riêng biệt là dấu chân bộ nhớ bổ sung. Nếu không, bạn đang ở trong khu vực có vấn đề của singletons (nơi chúng phải được khởi tạo để sử dụng, mọi thứ sử dụng chúng phải đảm bảo chúng được khởi tạo trước, và dĩ nhiên tất cả các mã được kết hợp cao với việc chúng được khởi tạo).

Trường hợp Singletons thực sự thực sự tồi tệ là nơi họ lưu trữ trạng thái để một lớp có thể thay đổi trạng thái và một lớp khác chọn nó. Về cơ bản, nó không phải là không có trong EJB cho đến 3.1, và thậm chí sau đó nó làm cho rất nhiều vấn đề tương tranh.

Chỉnh sửa (tiếp theo): Vì vậy, bạn muốn đi với kho lưu trữ lớp. Tôi sử dụng JBoss 4.2.3, vì vậy tôi không nhất thiết phải biết tất cả các ins and outs của JBoss5 (đã viết lại classloader của nó mặc dù họ nói nó gần như hoàn toàn tương thích ngược), tuy nhiên trong 4.2.x theo mặc định cấu hình của bạn không gây ra vấn đề bởi vì tất cả các tai được triển khai trên máy chủ chia sẻ cùng một trình nạp lớp ("trình nạp lớp thống nhất"). Điều tôi nghi ngờ là máy chủ bạn đang triển khai có cấu hình khác nhau, vì vậy tôi không báo chắc chắn cách tương tác với nó, nhưng những gì bạn phải làm là thêm một tệp có tên là jboss-app.xml vào tai bạn (trong cùng một vị trí như tệp application.xml) trông giống như sau:

<?xml version="1.0"?> 
<!DOCTYPE jboss-app PUBLIC "-//JBoss//DTD J2EE Application 4.2//EN" 
     "http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd"> 
<jboss-app> 
     <loader-repository> 
     com.yourcomany:archive=yourear 
     </loader-repository> 
</jboss-app> 

Đó là dành cho JBoss 4.2. 5.1 có cùng loại thẻ, dưới đây là xsd. Nó có cùng một khái niệm kho lưu trữ.

Điều đó nên. Tức là, miễn là cái bình, chiến tranh, vv của bạn không có nó, thế thì họ không cần nó. Tuy nhiên, các cuộc chiến của bạn (trong tệp jboss-web.xml - cùng một vị trí với tệp web.xml) có thể cần điều tương tự. Trong trường hợp này miễn là bạn đặt tên cho kho lưu trữ chính xác theo cùng một cách (nếu tôi hiểu chính xác - không bao giờ thử bản thân mình), chúng sẽ chia sẻ cùng một trình nạp lớp. Điều tương tự cũng xảy ra đối với EJB như được định cấu hình trong tệp jboss.xml có cùng vị trí với tệp ejb.xml.

This có thể làm cho nó rõ ràng hơn một chút.

+0

Tôi chắc chắn sẽ mở để được thuyết phục vào thời điểm này, nhưng tôi không biết khi nói đến J2EE (tôi không có đào tạo chính thức và về cơ bản vừa hoàn thành JIT học hỏi kể từ khi tôi bắt đầu làm việc trên các ứng dụng J2EE của công ty tôi). Vì vậy, tại sao nó xấu để chia sẻ nhà nước giữa WAR? Cách tôi nhìn thấy nó, mỗi WAR chỉ là một cái nhìn khác nhau vào ứng dụng của tôi. Một là dành cho người dùng hàng ngày và một là dành cho chức năng quản trị ứng dụng (như tạo/chỉnh sửa/xóa người dùng, quyền truy cập, v.v.). –

+0

Tôi mở rộng câu trả lời của mình để thảo luận về Singletons, nhưng các vấn đề với chúng không phải là J2EE cụ thể (mặc dù các ứng dụng cấp J2EE có một số vấn đề khi bạn nói về phân cụm, v.v.). – Yishai

+0

Sau khi tham khảo ý kiến ​​của các cấp cao hơn, mục tiêu hiện tại chỉ là làm cho mọi thứ hoạt động, và lo lắng về việc thực hiện đúng sau (aka, dự án tiếp theo). Tôi sẽ cố gắng sử dụng một trình nạp lớp cho toàn bộ EAR để giảm thiểu mã mà tôi cần phải thay đổi, nhưng có vẻ như có những từ bị thiếu trong [repository-repository] đó (http://community.jboss.org/wiki)/classloadingconfiguration) liên kết. Bất kỳ ý tưởng nơi tôi có thể tìm thấy một tài liệu đầy đủ về những gì tôi cần phải làm gì? –

1

Tôi sẽ định cấu hình một nhóm đối tượng riêng biệt trên máy chủ ứng dụng của bạn để nó chỉ chứa một cá thể duy nhất.

Tại sao bạn muốn thực hiện điều này là câu hỏi thực. Có vẻ như tất cả các ứng dụng của bạn sẽ được ghép theo cách này. Và Google is eradicating singleton từ các ứng dụng của nó. Tại sao bạn thấy phù hợp để đưa nó trở lại?

+0

Bạn có thể xây dựng một nhóm đối tượng riêng biệt không? Tôi khá mới đối với J2EE vì vậy tôi không thực sự biết điều đó có nghĩa là gì, đặc biệt trong các điều khoản thực tế/triển khai. Tại sao tôi muốn một singleton? Nó có vẻ như một giải pháp hợp lý cho nhu cầu của tôi - một nơi tập trung cho trạng thái kiên trì trong suốt cuộc đời của ứng dụng. Chúng bao gồm thông tin cấu hình ứng dụng và một lượng lớn dữ liệu được tải một lần từ cơ sở dữ liệu khi khởi động ứng dụng (được lưu trong bộ nhớ cache trong thời gian chạy sau đó). Tôi không phản đối việc sử dụng thứ gì khác ngoài singleton, nhưng tôi không biết giải pháp nào tốt hơn. –

+0

"Nó có vẻ như một giải pháp hợp lý cho nhu cầu của tôi - một nơi tập trung cho trạng thái kiên trì trong suốt cuộc đời của ứng dụng." - đó là những gì cơ sở dữ liệu nên cho. Bạn có biết rằng nó cần thiết để có tất cả trong bộ nhớ? Hiệu suất đó có phải là vấn đề hay bạn cho rằng đó sẽ là vấn đề? Một giải pháp tốt hơn là sử dụng bộ nhớ cache được phân phối như Terracotta được xây dựng cho việc này. Nó không dễ làm - đừng cho rằng bạn biết rõ hơn. – duffymo

1

Bạn có thể sử dụng MBean và liên kết nó với JNDI, sau đó truy xuất nó bất cứ nơi nào bạn muốn sử dụng nó.

Các MBean có thể được triển khai trong một file .sar

+0

Thật không may, JNDI tra cứu chậm (như tôi hiểu nó). Đó có thực sự là một lựa chọn khả thi, có khả năng mở rộng không? –

+1

Không nên quá chậm trong cùng một JVM. Trong trường hợp hiệu suất chi phí quá cao, bạn vẫn có thể lưu trữ kết quả tra cứu ở đâu đó – Guillaume

1

Nếu bạn đang sử dụng Java EE 6, thì nó hỗ trợ các EJB đơn lẻ.

+1

Tôi khá chắc chắn là không. Bạn đã bỏ lỡ một phần về JBoss 5.1 vs 6? –

0

Nếu thực tế, chỉ cần lấy lớp có singleton, đặt nó vào một JAR, lấy JAR OUT của EAR và thêm JAR vào trình nạp lớp JBoss (thông qua đường dẫn lớp hệ thống hoặc một thư mục lib nào đó). Điều này đặt lớp trong một trình nạp lớp đơn được chia sẻ bởi cả hai WAR.

Singleton sẽ không thể "xem" bất kỳ thứ gì trong các ứng dụng của bạn WARs, v.v., vì chúng nằm trong trình nạp lớp thấp hơn.

Tuy nhiên, không có gì ngăn cản bạn tiêm vào singleton (lúc khởi động máy chủ) một lớp nhà máy, bắt nguồn từ WAR và cộng sự, và lớp THAT có quyền truy cập vào tất cả các lớp ứng dụng. Điều đó làm cho singleton nhiều hơn một container đơn giản.

Nhưng điều này là đơn giản để làm.

Ngoài ra, nếu bạn làm điều này, hãy chắc chắn khi bạn tắt ứng dụng của bạn, rằng bất kỳ trường hợp nào được tổ chức bởi singleton này được giải phóng. Bất kỳ tham chiếu lớp nào của singleton sẽ không được GC'd khi bạn không triển khai ứng dụng. Vì vậy, nếu bạn có một tham chiếu đến ứng dụng của bạn được lưu trữ trong singleton, thì máy chủ giữ một tham chiếu đến trình nạp lớp đơn, trình nạp lớp đó giữ một tham chiếu đến lớp singleton của bạn, giữ tham chiếu đến lớp ứng dụng của bạn, chứa tham chiếu đến ứng dụng CLASSLOADER và THAT giữ tham chiếu đến tất cả các lớp trong ứng dụng của bạn. Không phải là một mớ hỗn độn tốt đẹp để lại phía sau.

+0

Tôi nghĩ rằng đoạn cuối cùng đưa ra một lý do chính đáng để tránh điều này. Khác là bạn mất khả năng triển khai nóng. – Yishai

+0

Bạn mất khả năng triển khai Singleton thật sự, nhưng không phải là phần còn lại của ứng dụng. Vì vậy, một khi phát triển chính đã xảy ra, yea, đó là một sự thật về việc thực hiện, nhưng có thể không phải là một vấn đề thực tế trên thế giới thực. Điều quan trọng là đảm bảo rằng vòng đời của ứng dụng hoạt động bình thường trong việc khởi động và rách xuống Singleton và các tài nguyên mà nó nắm giữ. Nó không phải là một gánh nặng khủng khiếp. Cuối cùng, Singleton có thể ít hơn một tham chiếu tĩnh trỏ đến logic thực tế, tinh vi trong chính ứng dụng. –

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