2017-02-17 16 views
14

Tôi đang xây dựng một công cụ CLI, tích hợp với một số mô-đun EJB. Vì lý do này, tôi cần phải xây dựng một fat jar, sau đó được thực hiện như một ứng dụng độc lập.Xây dựng một JAR thực thi độc lập với OpenEJB

Tuy nhiên, thực hiện này fat jar với java -jar (Lưu ý: conf/openejb.xml là trong cùng thư mục với các fat jar) không thành công với stacktrace sau:

INFORMATION - PersistenceUnit(name=demo, provider=org.hibernate.jpa.HibernatePersistenceProvider) - provider time 2706ms 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/MEJB!javax.management.j2ee.ManagementHome") 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/MEJB") 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/openejb/Deployer!org.apache.openejb.assembler.Deployer") 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/openejb/Deployer") 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/openejb/ConfigurationInfo!org.apache.openejb.assembler.classic.cmd.ConfigurationInfo") 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/openejb/ConfigurationInfo") 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/DemoServiceImpl!com.github.rzo1.service.DemoService") 
INFORMATION - Jndi(name="java:global/DemoMain/demo-shade-1.0-SNAPSHOT/DemoServiceImpl") 
INFORMATION - Existing thread singleton service in SystemInstance(): [email protected] 
INFORMATION - Closing DataSource: demoDS 
INFORMATION - Closing DataSource: demoDSNonJTA 
Exception in thread "Thread-0" java.lang.RuntimeException: org.apache.openejb.OpenEjbContainer$AssembleApplicationException: javax.enterprise.inject.spi.DeploymentException: couldn't start owb context 
     at com.github.rzo1.DemoMain.run(DemoMain.java:116) 
     at java.lang.Thread.run(Thread.java:745) 
Caused by: org.apache.openejb.OpenEjbContainer$AssembleApplicationException: javax.enterprise.inject.spi.DeploymentException: couldn't start owb context 
     at org.apache.openejb.OpenEjbContainer$Provider.createEJBContainer(OpenEjbContainer.java:346) 
     at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:56) 
     at com.github.rzo1.DemoMain.run(DemoMain.java:90) 
     ... 1 more 
Caused by: javax.enterprise.inject.spi.DeploymentException: couldn't start owb context 
     at org.apache.openejb.cdi.ThreadSingletonServiceImpl.initialize(ThreadSingletonServiceImpl.java:191) 
     at org.apache.openejb.cdi.CdiBuilder.build(CdiBuilder.java:41) 
     at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:913) 
     at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:717) 
     at org.apache.openejb.OpenEjbContainer$Provider.createEJBContainer(OpenEjbContainer.java:342) 
     ... 3 more 
Caused by: org.apache.webbeans.exception.WebBeansException: Wrong startup object. 
     at org.apache.webbeans.web.lifecycle.WebContainerLifecycle.getServletContext(WebContainerLifecycle.java:227) 
     at org.apache.webbeans.web.lifecycle.WebContainerLifecycle.startApplication(WebContainerLifecycle.java:86) 
     at org.apache.openejb.cdi.ThreadSingletonServiceImpl.initialize(ThreadSingletonServiceImpl.java:189) 
     ... 7 more 

Thực thi mã trực tiếp từ IDE của tôi (IntelliJ) container độc lập đi lên và cư xử như mong đợi.

Version Tóm tắt:

  • openejb trong phiên bản 1.7.0/openejb-server trong phiên bản 7.0.2
  • maven-shade-plugin trong phiên bản 2.4.3
  • Maven trong phiên bản 3.3.9
  • hibernate trong phiên bản 5.2.7

cơ bản cài đặt

tôi đã có thể để tái tạo vấn đề của tôi trên một ví dụ làm việc đơn giản, mà tôi thêm as an GitHub project để điều tra thêm.

Cách bố trí dự án cơ bản là như sau:

| # demo-shade 
    | - demo-services (EJB-Module)   
    | - demo-main (Shading happens here) 

Cấu hình của maven-shade-plugin là như sau:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-shade-plugin</artifactId> 
    <version>2.4.3</version> 
    <executions> 
     <execution> 
      <phase>package</phase> 
      <goals> 
       <goal>shade</goal> 
      </goals> 
      <configuration> 
       <finalName>demo-shade-${project.version}</finalName> 
       <transformers> 
        <transformer 
          implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> 
         <manifestEntries> 
          <Main-Class>com.github.rzo1.DemoMain</Main-Class> 
         </manifestEntries> 
        </transformer> 
        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> 
        <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> 
         <resource>META-INF/openwebbeans/openwebbeans.properties</resource> 
        </transformer> 
       </transformers> 
       <filters> 
        <filter> <!-- we don't want JSF to be activated --> 
         <artifact>*:*</artifact> 
         <excludes> 
          <exclude>META-INF/faces-config.xml</exclude> 
          <exclude>META-INF/*.SF</exclude> 
          <exclude>META-INF/*.DSA</exclude> 
          <exclude>META-INF/*.RSA</exclude> 
         </excludes> 
        </filter> 
       </filters> 
       <shadedClassifierName>dist</shadedClassifierName> 
      </configuration> 
     </execution> 
    </executions> 
</plugin> 

Mã để khởi động các container:

EJBContainer ejbContainer = null; 
    try { 
     final Properties properties = new Properties(); 
     properties.setProperty(EJBContainer.APP_NAME, applicationName); 
     properties.setProperty(EJBContainer.PROVIDER, OpenEjbContainer.class.getName()); 
     properties.setProperty(OpenEjbContainer.OPENEJB_EMBEDDED_REMOTABLE, "false"); 
     properties.setProperty("ejbd.disabled", "true"); 
     properties.setProperty("ejbds.disabled", "true"); 
     properties.setProperty("admin.disabled", "true"); 
     properties.setProperty("openejb.jaxrs.application", "false"); 

     Path launchPath = Paths.get(DemoMain.class.getProtectionDomain().getCodeSource().getLocation().toURI()); 
     properties.setProperty("openejb.configuration", launchPath.toAbsolutePath() + "/conf/openejb.xml"); 

     properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 
     properties.put("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver"); 

     // This is the line starting the EJB container 
     ejbContainer = EJBContainer.createEJBContainer(properties); 
     ejbContainer.getContext().bind("inject", this); 

     ejbContainerReady = true; 

     final CountDownLatch latch = new CountDownLatch(1); 
     // Graceful shutdown 
     Runtime.getRuntime().addShutdownHook(new Thread() { 
      @Override 
      public void run() { 
       try { 
        logger.info("Shutting down.."); 
        latch.countDown(); 
        logger.info("Shutdown completed successfully."); 
       } catch (final Exception e) { 
        logger.error("Graceful shutdown went wrong. SIGKILL (kill -9) if you want.", e); 
       } 
      } 
     }); 
     try { 
      latch.await(); 
     } catch (final InterruptedException e) { 
      // ignored 
     } 
    } catch (final Exception e) { 
     ejbContainerReady = false; 
     throw new RuntimeException(e); 
    } finally { 
     if (ejbContainer != null) { 
      ejbContainer.close(); 
     } 
    } 

} 

Câu hỏi

  • Tôi có bỏ sót điều gì đó trong cấu hình của maven-shade-plugin không?

  • Làm cách nào để tạo fat jar sử dụng openejb theo cách độc lập?

Ví dụ dự án

UPDATE 1:

Tôi đã thay đổi pom theo câu trả lời của P. Merkle.Tôi đã tìm thấy một bài viết khác here mô tả quá trình tô bóng dành riêng cho TomEE.

pom đổi thành

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-shade-plugin</artifactId> 
    <version>2.4.3</version> 
    <executions> 
     <execution> 
      <phase>package</phase> 
      <goals> 
       <goal>shade</goal> 
      </goals> 
      <configuration> 
       <finalName>demo-shade-${project.version}</finalName> 
       <transformers> 
        <transformer 
          implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> 
         <manifestEntries> 
          <Main-Class>com.github.rzo1.DemoMain</Main-Class> 
         </manifestEntries> 
        </transformer> 
        <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> 
        <transformer implementation="org.apache.openwebbeans.maven.shade.OpenWebBeansPropertiesTransformer"/> 
       </transformers> 
       <filters> 
        <filter> <!-- we don't want JSF to be activated --> 
         <artifact>*:*</artifact> 
         <excludes> 
          <exclude>META-INF/faces-config.xml</exclude> 
          <exclude>META-INF/*.SF</exclude> 
          <exclude>META-INF/*.DSA</exclude> 
          <exclude>META-INF/*.RSA</exclude> 
         </excludes> 
        </filter> 
       </filters> 
       <shadedClassifierName>dist</shadedClassifierName> 
      </configuration> 
     </execution> 
    </executions> 
    <dependencies> 
     <dependency> 
      <groupId>org.apache.openwebbeans</groupId> 
      <artifactId>openwebbeans-maven</artifactId> 
      <version>1.7.0</version> 
     </dependency> 
    </dependencies> 
</plugin> 

Extecuting này fat jar mang:

INFORMATION - OpenWebBeans Container is starting... 
INFORMATION - Adding OpenWebBeansPlugin : [CdiPlugin] 
SCHWERWIEGEND - CDI Beans module deployment failed 
java.lang.NullPointerException 
     at org.apache.openejb.cdi.CdiScanner.handleBda(CdiScanner.java:271) 
     at org.apache.openejb.cdi.CdiScanner.init(CdiScanner.java:148) 
     at org.apache.openejb.cdi.OpenEJBLifecycle.startApplication(OpenEJBLifecycle.java:179) 
     at org.apache.openejb.cdi.ThreadSingletonServiceImpl.initialize(ThreadSingletonServiceImpl.java:189) 
     at org.apache.openejb.cdi.CdiBuilder.build(CdiBuilder.java:41) 
     at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:913) 
     at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:717) 
     at org.apache.openejb.OpenEjbContainer$Provider.createEJBContainer(OpenEjbContainer.java:342) 
     at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:56) 
     at com.github.rzo1.DemoMain.run(DemoMain.java:90) 
     at java.lang.Thread.run(Unknown Source) 
INFORMATION - Closing DataSource: demoDS 
INFORMATION - Closing DataSource: demoDSNonJTA 
Exception in thread "Thread-0" java.lang.RuntimeException: org.apache.openejb.OpenEjbContainer$AssembleApplicationException: javax.enterprise.inject.spi.DeploymentException: couldn't start owb context 
     at com.github.rzo1.DemoMain.run(DemoMain.java:116) 
     at java.lang.Thread.run(Unknown Source) 
Caused by: org.apache.openejb.OpenEjbContainer$AssembleApplicationException: javax.enterprise.inject.spi.DeploymentException: couldn't start owb context 
     at org.apache.openejb.OpenEjbContainer$Provider.createEJBContainer(OpenEjbContainer.java:346) 
     at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:56) 
     at com.github.rzo1.DemoMain.run(DemoMain.java:90) 
     ... 1 more 
Caused by: javax.enterprise.inject.spi.DeploymentException: couldn't start owb context 
     at org.apache.openejb.cdi.ThreadSingletonServiceImpl.initialize(ThreadSingletonServiceImpl.java:191) 
     at org.apache.openejb.cdi.CdiBuilder.build(CdiBuilder.java:41) 
     at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:913) 
     at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:717) 
     at org.apache.openejb.OpenEjbContainer$Provider.createEJBContainer(OpenEjbContainer.java:342) 
     ... 3 more 
Caused by: org.apache.openejb.OpenEJBRuntimeException: java.lang.NullPointerException 
     at org.apache.openejb.cdi.OpenEJBLifecycle.startApplication(OpenEJBLifecycle.java:200) 
     at org.apache.openejb.cdi.ThreadSingletonServiceImpl.initialize(ThreadSingletonServiceImpl.java:189) 
     ... 7 more 
Caused by: java.lang.NullPointerException 
     at org.apache.openejb.cdi.CdiScanner.handleBda(CdiScanner.java:271) 
     at org.apache.openejb.cdi.CdiScanner.init(CdiScanner.java:148) 
     at org.apache.openejb.cdi.OpenEJBLifecycle.startApplication(OpenEJBLifecycle.java:179) 
     ... 8 more 

Tôi đã thêm một chi nhánh với điều này thay đổi trên GitHub Project để điều tra thêm.

UPDATE 2

tôi loại trừ javax.xml.* từ bóng râm:

<excludes> 
    <exclude>META-INF/faces-config.xml</exclude> 
    <exclude>META-INF/*.SF</exclude> 
    <exclude>META-INF/*.DSA</exclude> 
    <exclude>META-INF/*.RSA</exclude> 
    <exclude>javax/xml/**</exclude> 
</excludes> 

Tuy nhiên, ngoại lệ vẫn giữ nguyên như trong Cập nhật 1. Tôi đẩy một liên quan branch vào kho GitHub.

Vì vậy, câu hỏi của tôi là:

  • khác cần phải được loại trừ khỏi bóng râm?

Với sự giúp đỡ của các câu trả lời khác, cuối cùng tôi đã tìm được giải pháp làm việc để xây dựng một điện thoại độc lập fat jar.

UPDATE 3:

Các bước (bây giờ) là:

  1. Sử dụng OpenWebBeansPropertiesTransformer thay AppendingTransformer như đã nêu bởi P. Merkle

  2. Loại trừ java.xml.* trong bóng râm như đã nêu bởi Romain Manni-Bucau:

    <excludes> 
    <exclude>META-INF/faces-config.xml</exclude> 
    <exclude>META-INF/*.SF</exclude> 
    <exclude>META-INF/*.DSA</exclude> 
    <exclude>META-INF/*.RSA</exclude> 
    <exclude>javax/xml/**</exclude> 
    

  3. Thêm một scan.xml trong META-INF chỉ bao gồm gói/classes, mà phải được quét. phiên bản làm việc hiện tại có thể được tìm thấy here

Câu hỏi:

  • là của họ một cách chính thức hoặc tốt hơn để làm điều này?
+0

http://stackoverflow.com/questions/2707733/eager-auto-loading-of-ejb-load-ejb-on-startup- on-jboss, http://blog.eisele.net/2010/12/seven-ways-to-get-things-started-java.html – Ali786

+0

Đó không phải chính xác những gì tôi đang tìm kiếm ?! – rzo

Trả lời

1

Trường hợp ngoại lệ là do việc hợp nhất nhiều tệp openwebbeans.properties từ các mô-đun khác nhau thành một tệp thuộc tính duy nhất qua AppendingTransformer.

Điều này là do openwebbeans.properties file là structured in a special way:

Tất cả các tập tin chứa một đơn tài sản configuration.ordinal trong đó xác định 'quan trọng' của họ. Bất kỳ cài đặt nào từ một tệp thuộc tính có cấu hình cao hơn .ordinal sẽ ghi đè cài đặt từ một tệp có cấu hình thấp hơn.ordinal.

Bây giờ, nếu bạn kết hợp các tệp này một cách ngây thơ - như AppendingTransformer thì--, bạn sẽ kết thúc với nhiều thuộc tính thứ tự cạnh tranh trong cùng một tệp.

Giải pháp là thay thế AppendingTransformer bằng OpenWebBeansPropertiesTransformer, trong đó giữ lại mức độ ưu tiên khi hợp nhất.

Một ví dụ pom.xml có sẵn ở đây: http://openwebbeans.apache.org/meecrowave/meecrowave-maven/index.html


Tin xấu là, tuy nhiên, giải pháp này phát hiện ra một ngoại lệ:

java.lang.NullPointerException tại org.apache. openejb.cdi.CdiScanner.handleBda (CdiScanner.java:271)

Cho đến nay tôi chưa thể xác định nguyên nhân của điều đó.

+0

Cảm ơn bạn đã điều tra và gợi ý. Tôi đã cập nhật câu hỏi và thêm một chi nhánh liên quan vào dự án GitHub. – rzo

2

http://tomee.apache.org/advanced/shading/index.html và có thể http://tomee.apache.org/advanced/applicationcomposer/index.html cũng là điểm khởi đầu tốt.

Bây giờ có vẻ như bạn quét các lớp không mong muốn như xml một trong đó trình nạp lớp là rỗng. Có khả năng loại trừ javax.xml. * Khỏi quét hoặc thậm chí cả bóng râm và nó sẽ hoạt động

+0

Tại sao điều này sau đó hoạt động từ IntelliJ IDE? Addon trong classpath Jar so với classpath IDE là gì? Tài sản để loại trừ javax.xml. * Từ quét là gì? – rzo

+0

ide sẽ sử dụng classpath đầy đủ (vs bóng) và jar sẽ được loại trừ ra khỏi hộp, scan.xml có thể là một lựa chọn nhưng thực sự nghĩ rằng nó không nên trong bóng râm quá (jre lớp shouldnt được nhúng nói chung) –

+0

Vì vậy, những gì các loại "lớp học bất ngờ" khác là gì? Loại trừ javax.xml. * Từ bóng râm không dẫn đến ngoại lệ giống như – rzo

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