在maven下使用grails指定“提供的”依赖项

时间:2012-02-21 18:35:21

标签: grails maven build-dependencies

我有一个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文件。

我有两种情况:

  1. 我希望能够在命令行中使用“mvn grails:run-app”在本地运行我的grails应用程序。我在开发过程中使用它。
  2. 我希望能够通过部署maven创建的war文件在JBoss 5.1.0 GA中运行app。这就是我们在集成,测试和生产环境中所做的工作。
  3. 在JBoss中运行时,所有与JMS提供程序相关的依赖项都可用并由应用程序服务器提供。使用maven处理此问题的常规方法是在pom文件中声明这些依赖项,范围为“provided”。这将使这些依赖项可用于编译和单元测试,但将它们从war文件中排除。

    但是,当我使用“mvn grails:run-app”从命令行本地运行时,似乎这些依赖项在运行时不可用于grails,许多ClassNotFound等例外都证明了这一点。将范围更改为“编译”允许我在本地运行。但是,现在这些依赖项被打包到我的war文件中,这是我不想要的,并且在JBoss中运行时往往会破坏它们。

    我现在发现的解决方案(或解决方法)是在我的pom中包含这些JMS依赖项和默认(编译)作用域,并通过BuildConfig中的一些代码从war文件中删除这些jar(及其所有传递依赖项) .groovy(见下文)。这是有效的,但它很麻烦且容易出错,因为我必须列出每一个传递依赖(其中有很多!)。

    我尝试过的其他一些事情:

    起初,我想也许我可以在“grails.project.dependency.resolution / dependencies”部分中将所需的JMS依赖项添加到BuildConfig.groovy,并将它们完全保留在pom之外。但是,这不起作用,因为根据this link,在maven下运行grails时会忽略BuildConfig依赖项部分。

    我也注意到了“pom true”选项(在上面的链接中提到)并尝试使用它。但是,在尝试运行grails时:run-app,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.groovy:

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

2 个答案:

答案 0 :(得分: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

希望这有帮助。

答案 1 :(得分:1)

这已在Grails 2.0中“修复”。 grails的maven插件已更新,因此“提供”范围意味着在本地运行时依赖性可用,但未包含在war war文件中。