2011-12-12 16 views
7

Tôi muốn JBoss chỉ sử dụng các phụ thuộc nằm trong tập tin chiến tranh của tôi. Mỗi lần tôi triển khai tập tin chiến tranh này, JBoss vẫn sử dụng các lọ riêng của nó.Làm thế nào để sử dụng JPA2 trên JBoss 5.x? (hoặc Làm thế nào để loại bỏ vấn đề cách ly tải lớp?)

Đây là jboss-web.xml tôi sử dụng:

<?xml version="1.0" encoding="UTF-8"?> 
<jboss-web> 
    <class-loading java2ClassLoadingCompliance="false"> 
     <loader-repository> 
      my.package:loader=my-app.war 
      <loader-repository-config> 
       java2ParentDelegation=false 
      </loader-repository-config> 
     </loader-repository> 
    </class-loading> 
</jboss-web> 

jboss-classloading.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<classloading 
    xmlns="urn:jboss:classloading:1.0" 
    export-all="NON_EMPTY" 
    import-all="true" 
    parent-first="false"/> 

JBoss 5.1.0.GA

+0

Làm thế nào để bạn biết nó đang sử dụng các lọ riêng? – gkamal

+0

@gkamal Khi ứng dụng của tôi chạy, tôi nhận được một ngoại lệ 'NoSuchMethod'. – Stephan

+0

WAR có được triển khai riêng hay là một phần của EAR không? – CoolBeans

Trả lời

7

1> TÓM TẮT

Ban đầu, tôi đã thử cách ly tải lớp này để tải các khay Hibernate 3.6.4 với JBoss 5.1.0.GA.

Hoàn toàn KHÔNG thể thực hiện được. Có một số ma thuật dưới mui xe ngăn bạn sử dụng bất kỳ phiên bản Hibernate nào có hỗ trợ JPA2.

Tôi thực sự thất vọng rằng dự án JBoss không cung cấp một số loại bản vá hoặc gói dịch vụ để hỗ trợ JPA2 trên 5.1.0.GA.

2> CÁCH GIẢI QUYẾT: "The Kernel giải pháp"
tôi đã quản lý để sử dụng JPA2 với JBoss 5.1.0.GA tôi mô tả ở đây công thức nấu ăn của tôi. Nó là một bằng chứng về khái niệm bạn có thể sử dụng để làm cho giải pháp của riêng bạn.

Thành phần:

  • 1 WAR lưu trữ
  • 1 servlet
  • 1 ứng dụng độc lập java (J2SE)

Recipe:

Bước 1: Xây dựng ứng dụng độc lập (APP)

Ứng dụng này sẽ nhận được hướng dẫn từ servlet để sử dụng Hibernate.

Tôi để bạn lựa chọn phương thức liên lạc. Khi APP sử dụng JPA2, nó sẽ cần tệp persistence.xml nằm trong thư mục META-INF. Kể từ JBoss 5.x, khi bạn triển khai một WAR, JBoss sẽ quét WAR và tất cả các triển khai phụ của nó để tìm và triển khai các tệp persistence.xml mù quáng. Đổi tên tệp persistence.xml của bạn thành my-persistence.xml chẳng hạn. Sử dụng mã bên dưới khi bạn xây dựng EntityManagerFactory (Ngăn JBoss triển khai persistence.xml).

CẬP NHẬT: Phương pháp này hoạt động nhưng một số cảnh báo lạ được nâng lên bởi Hibernate. Để ngăn chặn những cảnh báo đó, tôi đã quyết định đặt thư mục META-INF và tệp kiên trì (được đổi tên thành persistence.xml bây giờ) bên ngoài WAR. Trong trường hợp của tôi, tôi đã chọn một thư mục cấu hình đặc biệt trên ổ cứng và thêm nó vào đường dẫn lớp. Không có cảnh báo lạ hơn và không có trình nạp lớp tùy chỉnh cần thiết để tải tệp kiên trì.

Tôi để bạn tùy chọn giữa việc sử dụng trình tải lớp tùy chỉnh hoặc thay đổi vị trí tệp kiên trì. Trong cả hai trường hợp, JBoss sẽ không tìm thấy tệp kiên trì.


Bước 2: Xây dựng các servlet

Khi servlet cần phải truy cập vào cơ sở dữ liệu, nó sẽ khởi động APP và nói với nó làm gì.

Để phát tán APP, servlet chịu trách nhiệm sinh sản một JVM mới và xây dựng đường dẫn lớp của APP. Đọc mã bên dưới để (Tạo một JVM). Classpath là dễ dàng thể xây dựng từ tất cả các lọ cần sẽ nằm trong thư mục /lib của các kho lưu trữ WAR ...


Bước 3: Xây dựng các kho lưu trữ WAR

Xây dựng một kho lưu trữ WAR nơi bạn đặt servlet và ứng dụng độc lập được đóng gói như một JAR. APP sẽ là phụ thuộc của WAR.


Ngăn chặn JBoss từ triển khai persistence.xml

// Install a proxy class loader for adding renamed persistence.xml file 
Thread t = Thread.currentThread(); 
ClassLoader clOriginal = t.getContextClassLoader(); 
t.setContextClassLoader(new SpecialClassLoader(clOriginal, "META-INF/my-persistence.xml")); 

// Build EntityManagerFactory 
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName); 

// Restore original class loader 
t.setContextClassLoader(clOriginal); 

//... 

private class ProxyClassLoader extends ClassLoader { 
    private ClassLoader realClassLoader; 
    private String hiddenFromJBossPersistenceFile; 

    public ProxyClassLoader(ClassLoader realClassLoader, String hiddenFromJBossPersistenceFile) { 
     this.realClassLoader = realClassLoader; 
     this.hiddenFromJBossPersistenceFile = hiddenFromJBossPersistenceFile; 
    } 

    public void clearAssertionStatus() { 
     realClassLoader.clearAssertionStatus(); 
    } 

    public boolean equals(Object obj) { 
     return realClassLoader.equals(obj); 
    } 

    public URL getResource(String name) { 
     return realClassLoader.getResource(name); 
    } 

    public InputStream getResourceAsStream(String name) { 
     return realClassLoader.getResourceAsStream(name); 
    } 

    public Enumeration<URL> getResources(String name) throws IOException { 
     ArrayList<URL> resources = new ArrayList<URL>(); 

     if (name.equalsIgnoreCase("META-INF/persistence.xml")) { 
      resources.add(getResource(this.hiddenFromJBossPersistenceFile)); 
     } 
     resources.addAll(Collections.list(realClassLoader.getResources(name))); 

     return Collections.enumeration(resources); 
    } 

    public int hashCode() { 
     return realClassLoader.hashCode(); 
    } 

    public Class<?> loadClass(String name) throws ClassNotFoundException { 
     return realClassLoader.loadClass(name); 
    } 

    public void setClassAssertionStatus(String className, boolean enabled) { 
     realClassLoader.setClassAssertionStatus(className, enabled); 
    } 

    public void setDefaultAssertionStatus(boolean enabled) { 
     realClassLoader.setDefaultAssertionStatus(enabled); 
    } 

    public void setPackageAssertionStatus(String packageName, boolean enabled) { 
     realClassLoader.setPackageAssertionStatus(packageName, enabled); 
    } 

    public String toString() { 
     return realClassLoader.toString(); 
    } 
} 

đẻ trứng một JVM

public static Process createProcess(final String optionsAsString, final String workingDir, final String mainClass, final String[] arguments) throws IOException { 
    String jvm = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"; 

    String[] options = optionsAsString.split(" "); 
    List<String> command = new ArrayList<String>(); 
    command.add(jvm); 
    command.addAll(Arrays.asList(options)); 
    command.add(mainClass); 
    command.addAll(Arrays.asList(arguments)); 

    //System.out.println(command); 

    ProcessBuilder processBuilder = new ProcessBuilder(command); 
    processBuilder.directory(new File(workingDir)); 

    return processBuilder.start(); 
} 

public static void makeItRun() { 
    try { 
     // Start JVM 
     String classPath = buildClassPath(); 
     String workingDir = getSuitableWorkingDir();//or just "." 
     Process java = createProcess("-cp \"" + classPath + "\"", workingDir, my.package.APP.class.getCanonicalName(), "-the -options -of -my -APP"); 

     // Communicate with your APP here ... 

     // Stop JVM 
     java.destroy(); 
    } catch(Throwable t) { 
     t.printStackTrace(); 
    } 
} 
1

Cấu hình ban đầu bạn đã đăng (JBoss-web.xml và jboss- classloading.xml) làm việc cho tôi trên EAP-5.12.

Rõ ràng JBoss-web.xml của

java2ClassLoadingCompliance="false" 

và/hoặc

<loader-repository-config> 
     java2ParentDelegation=false 
    </loader-repository-config> 

đang bị bỏ qua bởi Jboss. Xem http://docs.jboss.org/jbossesb/docs/4.10/manuals/html/Getting_Started_Guide/index.html#sect-scoped_deploy nơi điều này được đề cập (ấn bản cộng đồng, nhưng dường như cũng hợp lệ cho ấn bản may mắn của jboss)

Tôi đã vật lộn với điều này trong một thời gian dài. Rồi bỏ cuộc. Sau đó, gần đây đã xem lại nó và vấp phải giải pháp jboss-classloading.xml.

Nếu không có nó, tôi sẽ nhận được ClassCastException:

java.lang.ClassCastException: org.hibernate.ejb.HibernatePersistence không thể được đúc để javax.persistence.spi.PersistenceProvider

Tôi có một phiên bản mới hơn (3.6.0.Final) của hibernate-entitymanager trong chiến tranh hơn những gì được sử dụng bởi Jboss.

<dependency> 
    <groupId>org.hibernate</groupId> 
    <artifactId>hibernate-entitymanager</artifactId> 
    <version>3.6.0.Final</version> 
    <type>jar</type> 
    <scope>compile</scope> 
</dependency> 

Điều tuyệt vời về điều này, bây giờ nó hoạt động, tôi có thể triển khai cùng một cuộc chiến trên tomcat và jboss không. (tomcat trong đám mây cho một giải pháp sao lưu, và jboss trên "mặt đất".)

+0

Tuyệt vời nếu nó hoạt động cho bạn trên JBoss EAP-5.1.2 nhưng ban đầu tôi không có lựa chọn để làm việc với JBoss 5.1.0.GA;) – Stephan

1

Đồng ý. Chúng tôi lấy các bước sau:

Các JAR sau tập tin cần phải được loại bỏ khỏi jboss_home/common/lib:

  • EJB3-persistence.jar (chúng tôi sẽ sử dụng thực hiện Hibernate cho JPA 2.0)
  • hibernate-annotations.jar (hiện nay là một phần của chế độ ngủ đông-core)
  • ngủ đông-c3p0.jar hibernate-commons-annotations.jar
  • ngủ đông-core.jar hibernate-entitymanager.jar
  • ngủ đông-validator.jar

Thêm lọ nâng cấp sau để jboss_home/common/lib:

  • hibernate-c3p0-3.6.10.Final.jar
  • hibernate-commons-annotations- 3.2.0.Final.jar
  • hibernate-core-3.6.10.Final.jar
  • ngủ đông-EntityManager-3.6.10.Final.jar
  • ngủ đông-JPA-2,0-api-1.0.1. Final.jar
  • hibernate-validator-4.2.0.Final.jar
  • validation-api-1.0.0.GA.jar (phụ thuộc của hibernate-validator)

Thêm tập tin (ví dụ) my-war\src\main\webapp\WEB-INF\jboss-classloading.xml

Ghi đè chính sách tải lớp mặc định để đảm bảo các lớp ngủ đông trong chiến tranh của bạn được sử dụng thay cho bất kỳ thư viện máy khách JBoss nào. Điều này có thể được thực hiện bằng cách thêm một tệp tin jboss-classloading.xml vào thư mục 'my-war/src/main/webapp/WEB-INF'. Dòng nhập cần lưu ý là đặt thuộc tính cha-đầu tiên thành false.

<?xml version="1.0" encoding="UTF-8"?> 
<classloading xmlns="urn:jboss:classloading:1.0" 
    export-all="NON_EMPTY" 
    import-all="true" 
    parent-first="false"> 
</classloading> 

Rename (ví dụ) '/src/main/resources/META-INF/persistence.xml'

JBoss sẽ cố gắng một cách mù quáng tải bất kỳ tập tin persistence.xml tồn tại trong một thư mục META-INF trên classpath. Vì trình triển khai siêu dữ liệu đơn vị bền vững được vận chuyển với JBoss chỉ hỗ trợ JPA 1.0, chúng ta cần vô hiệu hóa hành vi này và ủy quyền nó cho Spring. Điều này có thể dễ dàng được thực hiện bằng cách đổi tên persistence.xml thành (ví dụ) /src/main/resources/META-INF/my-persistence.xml

Cập nhật '/src/main/resources/spring-jpaaccess.xml'

Cập nhật cấu hình ngữ cảnh ứng dụng Spring (ví dụ) '/src/main/resources/spring-jpaaccess.xml' và thêm persistenceXmlLocation như sau.

<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="persistenceUnitName" value="myPU" /> 
    <property name="persistenceXmlLocation" value="classpath:META-INF/my-persistence.xml" /> 
/bean> 
Các vấn đề liên quan