2012-02-21 63 views
2

我有一個grails 1.3.7應用程序。我正在使用Spring的JMS類來設置我的一個Grails服務作爲消息監聽器,在grails-app/conf/resources.groovy中設置這些類。我正在使用maven 2.0.9進行構建,使用grails-maven-plugin 1.3.7和「maven-war」目標來創建一個war文件。在maven下使用grails指定「提供」依賴項

我有兩個方案:

  1. 我希望能夠給應用程序在本地運行Grails的我,在命令行中,使用「MVN的Grails:運行應用程序」。我在開發過程中使用它。
  2. 我希望能夠通過部署由maven創建的war文件在JBoss 5.1.0 GA中運行應用程序。這就是我們在集成,測試和生產環境中所做的。

當在JBoss運行,所有的JMS提供者相關的依賴性都可用,由應用服務器提供。用maven處理這個問題的正常方法是在pom文件中聲明這些依賴項,範圍爲「provided」。這將使這些依賴關係可用於編譯和單元測試,但將它們從war文件中排除。

但是,當我使用「mvn grails:run-app」從命令行本地運行時,似乎這些依賴關係在運行時不可用於grails,正如許多ClassNotFound等異常所證明的那樣。將範圍更改爲「編譯」允許我在本地運行。然而,現在這些依賴關係被打包到我的war文件中,我不想在JBoss中運行這些文件,而這些文件往往會破壞它。

我現在發現的解決方案(或解決方法)是在我的pom中包含這些具有默認(編譯)範圍的JMS依賴項,並通過一些代碼從war文件中刪除這些jar(以及它們的所有傳遞依賴項) BuildConfig.groovy(見下文)。這有效,但它很麻煩,容易出錯,因爲我必須列出每個傳遞依賴項(其中有很多!)。

我曾嘗試一些其他的事情:

起初,我想我或許能所需的JMS依賴性增加BuildConfig.groovy的「grails.project.dependency.resolution /依存關係」部分,並留下他們完全離開了pom。但是,這不起作用,因爲根據this link,在maven下運行grails時,忽略了BuildConfig依賴項部分。

我還注意到「pom true」選項(在上面的鏈接中提到)並試圖使用它。但是,試圖運行的Grails時:運行應用程序,Grails的拋出有關未解決的依賴關係的警告,並給出了tomcat的錯誤:

:::: WARNINGS 
:::::::::::::::::::::::::::::::::::::::::::::: 
::   UNRESOLVED DEPENDENCIES   :: 
:::::::::::::::::::::::::::::::::::::::::::::: 
:: commons-collections#commons-collections;3.2.1: configuration not found in commons-collections#commons-collections;3.2.1: 'master'. It was required from org.grails.internal#load-manager-grails;1.2-SNAPSHOT compile 
:: org.slf4j#slf4j-api;1.5.8: configuration not found in org.slf4j#slf4j-api;1.5.8: 'master'. It was required from org.grails.internal#load-manager-grails;1.2-SNAPSHOT runtime 

... 

java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.apache.tomcat.util.digester.Digester.setDocumentLocator(Lorg/xml/sax/Locator;)V" the class loader (instance of org/codehaus/groovy/grails/cli/support/GrailsRootLoader) of the current class, org/apache/tomcat/util/digester/Digester, and its superclass loader (instance of <bootloader>), have different Class objects for the type org/xml/sax/Locator used in the signature 
     at org.grails.tomcat.TomcatServer.start(TomcatServer.groovy:212) 

我的問題: 有沒有更好的辦法 - 通過Grails和/或Maven的配置選項 - 完成我想要的東西 - 即能夠在本地和JBoss內成功運行grails,而不必從war文件中手動排除所有傳遞依賴關係?

注意:我無法更改我正在使用的grails,JBoss或maven的版本。

相關文件中的一些摘錄:

BuildConfig。常規:

grails.project.class.dir = "target/classes" 
grails.project.test.class.dir = "target/test-classes" 
grails.project.test.reports.dir = "target/test-reports" 
grails.project.war.file = "target/${appName}-${appVersion}.war" 

grails.project.dependency.resolution = { 
    // inherit Grails' default dependencies 
    inherits("global") { 
     // uncomment to disable ehcache 
     // excludes 'ehcache' 
    } 
    log "warn" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose' 
    repositories { 
     // only use our internal Archiva instance 
     mavenRepo "http://my-company.com/archiva/repository/mirror" 
     mavenLocal() 
    } 
    dependencies { 
     // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg. 
    } 

    //Remove own log4j and use the one supplied by JBoss instead 
    grails.war.resources = {stagingDir -> 
     delete file:"$stagingDir/WEB-INF/classes/log4j.properties" // logging conf done in JBoss only 

     def files = fileScanner { 
      fileset(dir:"$stagingDir/WEB-INF/lib"){ 
       [ 
        // all of the following are jms-related dependencies supplied by JBoss 
        /* org.jboss.javaee */ "jboss-jms-api-*.jar", 
        /* org.jboss.naming */ "jnp-client-*.jar", 
        /* org.jboss */ "jboss-common-core-*.jar", 
        /* org.jboss.logging */ "jboss-logging-spi-*.jar", 
        /* jboss.messaging */ "jboss-messaging-*.jar", 
        /* org.jboss.aop */ "jboss-aop-*.jar", 
        /* org.apache.ant */ "ant-*.jar", 
        /*  org.apache.ant */ "ant-launcher-*.jar", 
        /* org.jboss */ "jboss-reflect-*.jar", 
        /* org.jboss */ "jboss-mdr-*.jar", 
        /* qdox */ "qdox-*.jar", 
        /* trove */ "trove-*.jar", 
        /* org.jboss.logging */ "jboss-logging-log4j-*.jar", 
        /* org.jboss.remoting */ "jboss-remoting-*.jar", 
        /* jboss */ "jboss-serialization-*.jar", 
        /* oswego-concurrent */ "concurrent-*.jar", 
        /* org.jboss.jbossas */ "jboss-as-cluster-*-jboss-ha-legacy-client.jar", 
        /* commons-logging */ "commons-logging-*.jar", 
        /* org.jboss.jbossas */ "jboss-as-server-*.jar", 
        /*  sun-jaxb */ "jaxb-api-*.jar", 
        /*  org.jboss.jbossas */ "jboss-as-deployment-*.jar", 
        /*   org.jboss.javaee */ "jboss-jad-api-*.jar", 
        /*   org.jboss.security */ "jboss-security-spi-*.jar", 
        . . . // and the other 74 transitive dependencies... 
       ].each{ 
        include(name:it) 
       } 
      } 
     } 
     files.each 
     { 
      delete(file: it) 
     } 

    } 
} 

的pom.xml:

<?xml version="1.0" encoding="utf-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 

    . . . 

    <dependencies> 

     . . . 

     <dependency> 
      <!-- already a dep of grails-crud; make it scope:compile for resources.groovy --> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-jms</artifactId> 
      <version>3.0.5.RELEASE</version> 
     </dependency> 
     <!-- Note: all the remaining jms dependencies below should be 'provided' scope, but 
      grails doesn't correctly pull them in when running locally, so we must leave 
      them as compile scope and remove them (and their transitive dependencies) from 
      the war file through BuildConfig.groovy 
     --> 
     <dependency> 
      <groupId>org.jboss.javaee</groupId> 
      <artifactId>jboss-jms-api</artifactId> 
      <version>1.1.0.GA</version> 
     </dependency> 
     <dependency> 
      <groupId>org.jboss.naming</groupId> 
      <artifactId>jnp-client</artifactId> 
      <version>5.0.3.GA</version> 
     </dependency> 
     <dependency> 
      <groupId>jboss.messaging</groupId> 
      <artifactId>jboss-messaging</artifactId> 
      <version>1.4.3.GA</version> 
     </dependency> 
     <dependency> 
      <groupId>org.jboss.aop</groupId> 
      <artifactId>jboss-aop</artifactId> 
      <version>2.1.1.GA</version> 
      <classifier>client</classifier> 
      <exclusions> 
       <exclusion> 
        <!-- see http://jira.codehaus.org/browse/GROOVY-3356 --> 
        <groupId>apache-xerces</groupId> 
        <artifactId>xml-apis</artifactId> 
       </exclusion> 
      </exclusions> 
     </dependency> 
     <dependency> 
      <groupId>org.jboss.remoting</groupId> 
      <artifactId>jboss-remoting</artifactId> 
      <version>2.5.3.SP1</version> 
     </dependency> 
     <dependency> 
      <groupId>jboss</groupId> 
      <artifactId>jboss-serialization</artifactId> 
      <version>1.0.3.GA</version> 
     </dependency> 
     <dependency> 
      <groupId>oswego-concurrent</groupId> 
      <artifactId>concurrent</artifactId> 
      <version>1.3.4-jboss-update1</version> 
     </dependency> 
     <!-- the following two are required in order to connect to HA-JNDI --> 
     <dependency> 
      <groupId>org.jboss.jbossas</groupId> 
      <artifactId>jboss-as-cluster</artifactId> 
      <classifier>jboss-ha-legacy-client</classifier> 
      <version>5.1.0.GA</version> 
     </dependency> 
     <dependency> 
      <groupId>org.jboss.cluster</groupId> 
      <artifactId>jboss-ha-client</artifactId> 
      <version>1.1.1.GA</version> 
     </dependency> 

     <!-- End dependencies for connecting to JMS --> 

    </dependencies> 

    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.grails</groupId> 
       <artifactId>grails-maven-plugin</artifactId> 
       <version>1.3.7</version> 
       <extensions>true</extensions> 
       <executions> 
        <execution> 
         <goals> 
          <goal>init</goal> 
          <goal>maven-clean</goal> 
          <goal>validate</goal> 
          <goal>config-directories</goal> 
          <goal>maven-compile</goal> 
          <goal>maven-test</goal> 
          <goal>maven-war</goal> 
          <goal>maven-functional-test</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

resources.groovy:

import org.codehaus.groovy.grails.commons.ConfigurationHolder 
import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter 
import org.springframework.jms.listener.DefaultMessageListenerContainer 
import org.springframework.jms.listener.adapter.MessageListenerAdapter 
import org.springframework.jms.support.destination.JndiDestinationResolver 
import org.springframework.jndi.JndiObjectFactoryBean 
import org.springframework.jndi.JndiTemplate 

beans = { 

    def config = ConfigurationHolder.config 

    jndiTemplate(JndiTemplate) { 
     environment = config.myQueue.ctx.toProperties() // flattens a{b{c}} to 'a.b.c' 
    } 

    jmsFactory(JndiObjectFactoryBean) { 
     jndiTemplate = jndiTemplate 
     jndiName = config.myQueue.connectionFactory as String 
     lookupOnStartup = false // need this? 
     proxyInterface = "javax.jms.ConnectionFactory" 
    } 

    authJmsFactory(UserCredentialsConnectionFactoryAdapter) { 
     targetConnectionFactory = jmsFactory 
     username = config.app.auth.username as String 
     password = config.app.auth.password as String 
    } 

    destinationResolver(JndiDestinationResolver) { 
     jndiTemplate = jndiTemplate 
    } 

    jmsMessageListener(MessageListenerAdapter, ref("myMessageDrivenService")) { 
     defaultListenerMethod = "onEventMessage" 
    } 

    jmsContainer(DefaultMessageListenerContainer) { 
     connectionFactory = authJmsFactory 
     destinationResolver = destinationResolver 
     destinationName = config.eventQueue.queueName as String 
     messageListener = jmsMessageListener 
     transactionManager = ref("transactionManager") // grails' txn mgr 
     cacheLevel = DefaultMessageListenerContainer.CACHE_CONNECTION 
     autoStartup = false // started up in Bootstrap.groovy 
    } 
} 
+0

這個問題已經在Grails 2.0中解決了。請參閱下面的[我的答案](http://stackoverflow.com/a/12692976/539048)。 – GreenGiant 2013-04-10 23:36:16

回答

1

對此的解決方案是通過一個配置文件來創建你所依賴的動態範圍。

例子:

<?xml version="1.0" encoding="utf-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 

. . . 
<properties> 
    <jms.deps.scope>compile</jms.deps.scope> 
</properties> 

<profile> 
    <id>build</id> 
    <properties> 
     <jms.deps.scope>provided</jms.deps.scope> 
    </properties> 
</profile> 

<dependencies> 
    <dependency> 
     <groupId>whatever</groupId> 
     <artifactId>whatever</artifactId> 
     <scope>${jms.deps.scope}</scope> 
    </dependency> 
</dependencies> 

. . . 

那麼當你的命令行將指定配置文件:

mvn clean install war -P build 

希望這有助於。

+0

這大部分工作。一些依賴仍然必須通過BuildConfig.groovy從war文件中刪除,因爲在運行編譯步驟(在這種情況下,jboss-jms-api)時,grails似乎忽略了「提供的」依賴關係。我還必須刪除由grails插件(即hibernate及其依賴項)引入的jar。最後,grails的集成測試無法正常運行,因爲grails沒有提供必要的「提供」依賴。但最終的結果是大約少了101行代碼。 – GreenGiant 2012-05-07 17:53:03

1

這已經在Grails 2.0中「固定」了。 grails的maven插件已更新,因此「提供」範圍意味着依賴關係在本地運行時可用,但未包含在程序包war文件中。