2017-02-17 5 views
14

Я создаю инструмент CLI, который интегрируется с несколькими модулями EJB. По этой причине мне нужно построить fat jar, который затем выполняется как отдельное приложение.Создание автономного исполняемого JAR с OpenEJB

Однако выполнение этого fat jar с java -jar (Примечание: conf/openejb.xml находится в том же каталоге, что и fat jar) выдает следующее StackTrace:

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 

Выполнение кода непосредственно из моего IDE (IntelliJ) автономный контейнер появляется и ведет себя так, как ожидалось.

Версия Резюме:

  • openejb в версии 1.7.0/openejb-server в версии 7.0.2
  • maven-shade-plugin в версии 2.4.3
  • Maven в версии 3.3.9
  • hibernate в версии 5.2.7

Основные настройки

Я был в состоянии воспроизвести мою проблему на простой рабочий пример, который я добавил as an GitHub project для дальнейшего исследования.

Базовая схема проекта заключается в следующем:

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

Конфигурация maven-shade-plugin выглядит следующим образом:

<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> 

код для запуска контейнера:

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(); 
     } 
    } 

} 

Вопросы

  • Я пропустил что-то в конфигурации maven-shade-plugin?

  • Как я могу построить fat jar с помощью openejb в автономном режиме?

Пример проекта

UPDATE 1:

Я изменил ПОМ согласно ответу П. Merkle.Я нашел еще одну статью here, описывающую процесс затенения специально для TomEE.

pom изменен

<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 это fat jar приносит:

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 

Я добавил ветку с этим меняется на GitHub Project для дальнейшего исследования.

UPDATE 2

я исключил javax.xml.* из тени:

<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> 

Однако исключение остается такой же, как и в Update 1. Я оттолкнул связанный branch в хранилище GitHub.

Так что мой вопрос:

  • Что еще должен быть исключен из тени?

С помощью других ответов я, наконец, смог найти рабочее решение для создания автономного fat jar, который работает на мой случай использования.

ОБНОВЛЕНИЕ 3:

Стадии (на данный момент) являются:

  1. Использование OpenWebBeansPropertiesTransformer вместо AppendingTransformer как заявлено P. Merkle

  2. Исключить java.xml.* в тени, как заявлено 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. Добавить scan.xml в META-INF включая только пакеты/классы, которые должны сканироваться. Текущая рабочая версия может быть найдена here

Вопрос:

  • Является ли их официальный или лучший способ сделать это?
+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

Это не совсем то, что я ищу ?! – rzo

ответ

1

Исключение вызвано объединение нескольких openwebbeans.properties файлов из различных модулей в единый файл свойств с помощью AppendingTransformer.

Это потому, что openwebbeans.properties файлы structured in a special way:

Все эти файлы содержат одного свойство configuration.ordinal, который определяет их 'важности'. Любая настройка из файла свойств с более высокой конфигурацией .ординарный будет перезаписывать настройки с одного с более низкой конфигурацией.

Теперь, если вы наивно объединить эти файлы - в AppendingTransformer does--, вы будете в конечном итоге с несколькими конкурирующими порядковых свойств в одном файле.

Решение заменить AppendingTransformer с OpenWebBeansPropertiesTransformer, который сохраняет приоритеты при слиянии.

Пример pom.xml доступен здесь: http://openwebbeans.apache.org/meecrowave/meecrowave-maven/index.html


Плохая новость, однако, что это решение открывает еще одно исключение:

java.lang.NullPointerException на org.apache. openejb.cdi.CdiScanner.handleBda (CdiScanner.java:271)

до сих пор я не был в состоянии определить причину этого.

+0

Спасибо за ваше исследование и подсказки. Я обновил вопрос и добавил связанный филиал по проекту GitHub. – rzo

2

http://tomee.apache.org/advanced/shading/index.html и, возможно, http://tomee.apache.org/advanced/applicationcomposer/index.html также являются хорошими отправными точками.

Теперь кажется, что вы сканируете неожиданные классы, такие как xml, где classloader равен null. Вероятно исключить javax.xml. * Из сканирования или даже тени, и он будет работать

+0

Почему это работает от IntelliJ IDE? Что такое аддон в пути Jar classpath по сравнению с пути класса IDE? Каково свойство исключать javax.xml. * Из сканирования? – rzo

+0

ide будет использовать полный путь к классам (vs shade), а jar будет исключен из thebox, scan.xml может быть вариантом, но действительно думаю, что он тоже не должен быть в тени (классы jre не должны быть встроены вообще) –

+0

Так что являются ли другие типы «неожиданных классов»? Исключение javax.xml. * Из тени приводит к тому же исключению – rzo

Смежные вопросы