2012-02-21 30 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文件中。