Frage

Ich habe eine Grails 1.3.7-Anwendung. Ich verwende die JMS-Klassen von Spring, um einen meiner Grails-Dienste als Nachrichten-Listener einzurichten und diese Klassen in grails-app / conf / resources.groovy einzurichten. Ich verwende Maven 2.0.9 für Builds, verwende das Grails-Maven-Plugin 1.3.7 und das Ziel "Maven-War", um eine War-Datei zu erstellen.

Ich habe zwei Szenarien:

  1. Ich möchte meine Grails-App lokal über die Befehlszeile mit "mvn grails: run-app" ausführen können. Ich benutze dies während der Entwicklung.
  2. Ich möchte die App in JBoss 5.1.0 GA ausführen können, indem ich die von maven erstellte Kriegsdatei bereitstelle. Dies tun wir in unseren Integrations-, Test- und Produktionsumgebungen.

    Wenn Sie in JBoss ausgeführt werden, sind alle Abhängigkeiten im Zusammenhang mit JMS-Anbietern verfügbar und werden vom Anwendungsserver bereitgestellt. Die normale Methode, dies mit maven zu behandeln, besteht darin, diese Abhängigkeiten in der pom-Datei mit dem Gültigkeitsbereich "bereitgestellt" zu deklarieren. Dadurch werden diese Abhängigkeiten für Kompilierungs- und Komponententests verfügbar, sie werden jedoch aus der War-Datei ausgeschlossen.

    Wenn ich jedoch lokal über die Befehlszeile mit "mvn grails: run-app" ausführe, scheinen diese Abhängigkeiten für Grails zur Laufzeit nicht verfügbar zu sein, wie viele Ausnahmen von ClassNotFound usw. belegen. Durch Ändern des Bereichs in "Kompilieren" kann ich lokal ausgeführt werden. Jetzt werden diese Abhängigkeiten jedoch in meine Kriegsdatei gepackt, was ich nicht möchte und dazu neige, Dinge zu beschädigen, wenn ich in JBoss ausgeführt werde.

    Die Lösung (oder Problemumgehung), die ich im Moment gefunden habe, besteht darin, diese JMS-Abhängigkeiten mit dem Standardbereich (Kompilieren) in meinen POM aufzunehmen und diese Jars (und alle ihre transitiven Abhängigkeiten) durch Code in BuildConfig aus der War-Datei zu entfernen .groovy (siehe unten). Dies funktioniert, ist aber chaotisch und fehleranfällig, da ich jede einzelne transitive Abhängigkeit auflisten muss (von denen es viele gibt!).

    Einige andere Dinge, die ich versucht habe:

    Zuerst dachte ich, ich könnte BuildConfig.groovy im Abschnitt "grails.project.dependency.resolution / dependencies" die erforderlichen JMS-Abhängigkeiten hinzufügen und sie vollständig aus dem POM herauslassen. Dies funktionierte jedoch nicht, da laut this link wird der Abschnitt BuildConfig-Abhängigkeiten ignoriert, wenn Grails unter maven ausgeführt werden.

    Ich habe auch die Option "pom true" (im obigen Link erwähnt) bemerkt und versucht, sie zu verwenden. Wenn Sie jedoch versuchen, grails: run-app auszuführen, gibt grails Warnungen vor ungelösten Abhängigkeiten aus und gibt einen Tomcat-Fehler aus:

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

    Meine Frage: Gibt es eine bessere Möglichkeit - durch Grails und / oder Maven-Konfigurationsoptionen - das zu erreichen, was ich möchte - dh Grails lokal und innerhalb von JBoss erfolgreich ausführen zu können, ohne alle transitiven Abhängigkeiten manuell aus der War-Datei ausschließen zu müssen?

    Hinweis: Ich kann die von mir verwendete Version von Grails, JBoss oder Maven nicht ändern.

    Einige Auszüge relevanter Dateien:

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

War es hilfreich?

Lösung

Die Lösung hierfür besteht darin, über ein Profil einen dynamischen Bereich für Ihre Abhängigkeit zu erstellen.

Beispiel:

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

. . .

Wenn Ihre Befehlszeile das Profil angibt:

mvn clean install war -P build

Hoffe das hilft.

Andere Tipps

Dies wurde in Grails 2.0 "behoben".Das Maven-Plugin für Grails wurde aktualisiert, sodass der "bereitgestellte" Bereich bedeutet, dass die Abhängigkeit bei lokaler Ausführung verfügbar ist, jedoch nicht in der Paketkriegsdatei enthalten ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top