У меня есть приложение Граальс 1.3.7.Я использую классы Spring JMS для настройки одной из моих служб grails в качестве прослушивателя сообщений, настраивая эти классы в grails-app / conf / resources.groovy.Я использую maven 2.0.9 для сборок, использую grails-maven-plugin 1.3.7 и цель "maven-war" для создания файла войны.
У меня есть два сценария:
- Я хочу иметь возможность запускать мое приложение grails локально, из командной строки, используя "mvn grails: run-app".Я использую это во время разработки.
- Я хочу иметь возможность запускать приложение в JBoss 5.1.0 GA, развертывая файл war, созданный maven.Это то, что мы делаем в наших средах интеграции, тестирования и производства.
При работе в JBoss все зависимости, связанные с JMS-провайдером, доступны и предоставляются сервером приложений.Обычный способ справиться с этим с помощью maven - объявить эти зависимости в pom-файле с областью «предоставлено».Это сделает эти зависимости доступными для компиляции и модульных тестов, но исключит их из файла war.
Однако, когда я запускаю локально из командной строки, используя «mvn grails: run-app», кажется, что этиЗависимости недоступны для Grails во время выполнения, что подтверждается многими исключениями ClassNotFound и т. д.Изменение области действия на «compile» позволяет мне работать локально.Тем не менее, теперь эти зависимости упакованы в мой war-файл, который я не хочу и склонен ломать вещи при работе внутри JBoss.
Решение (или обходной путь), который я нашел на данный момент, состоит в том, чтобы включить эти зависимости JMSс областью по умолчанию (compile) в моем pom, и удалите эти файлы jar (и все их транзитивные зависимости) из файла war через некоторый код в BuildConfig.groovy (см. ниже).Это работает, но это грязно и подвержено ошибкам, потому что я должен перечислить все транзитивные зависимости (которых много!).
Некоторые другие вещи, которые я пробовал:
Сначала яподумал, что, возможно, я мог бы добавить необходимые JMS-зависимости в BuildConfig.groovy в разделе «grails.project.dependency.resolution / dependencies» и полностью исключить их из pom.Однако это не сработало, потому что, согласно этой ссылке , раздел зависимостей BuildConfig игнорируется при запуске grails под maven.
Я также заметил параметр «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 - чтобы выполнить то, что я хочу - т.е. иметь возможность успешно запускать grails локально и в JBoss, без необходимости вручную исключать все переходные зависимости из файла 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
}
}