El complemento proporciona capacidades de implementación de aplicaciones web a un contenedor web Tomcat integrado en cualquier compilación de Gradle. Extiende el complemento de guerra. En el momento en que las versiones Tomcat 6.0.x, 7.0.x, 8.0.x, 8.5.x y 9.0.x son compatibles.
El caso de uso típico para este complemento es admitir la implementación durante el desarrollo. El complemento permite un desarrollo rápido de aplicaciones web debido a los tiempos de inicio rápidos del contenedor. Gradle comienza el contenedor incrustado en el mismo JVM. Actualmente, el contenedor no puede bifurcarse como un proceso separado. Este complemento tampoco puede implementar un archivo de guerra en un contenedor remoto. Si está buscando esta capacidad, eche un vistazo al complemento de carga.
Para usar la funcionalidad del complemento, deberá agregar el artefacto binario ITS al classpath de su script de compilación y aplicar el complemento.
El jar del complemento debe definirse en la classpath de su script de compilación. Está directamente disponible en el portal de complemento de Gradle. El siguiente fragmento de código muestra un ejemplo sobre cómo recuperarlo:
buildscript {
repositories {
gradlePluginPortal()
}
dependencies {
classpath ' com.bmuschko:gradle-tomcat-plugin:2.7.0 '
}
}El archivo jar viene con dos complementos:
| Identificador de complemento | Depende de | Tipo | Descripción |
|---|---|---|---|
| com.bmuschko.tomcat-base | - | Tomcatbaseplugin | Proporciona tipos de tareas personalizados Tomcat, classpath previo a las configuras. |
| com.bmuschko.tomcat | com.bmuschko.tomcat-base | Tomcatplugin | Proporciona tareas para comenzar y detener un contenedor Tomcat incrustado y expone una extensión llamada tomcat . |
El complemento com.bmuschko.tomcat te ayuda a comenzar rápidamente. Si está bien si las tareas preconfiguradas, esta es la opción preferible. La mayoría de los usuarios de complementos irán con esta opción. Para usar el complemento TomCat, incluya el siguiente fragmento de código en su script de compilación:
apply plugin: 'com.bmuschko.tomcat'
Si necesita control total sobre sus tareas o no desea ir con las tareas preconfiguradas, querrá usar el complemento com.bmuschko.tomcat-base . Ese podría ser el caso si desea configurar el contenedor únicamente para pruebas funcionales. La desventaja es que cada tarea debe configurarse individualmente en su script de compilación. Para usar el complemento base Tomcat, incluya el siguiente fragmento de código en su script de compilación:
apply plugin: 'com.bmuschko.tomcat-base'
Además, las bibliotecas de tiempo de ejecución de Tomcat deben agregarse a la configuración tomcat . En este momento, las versiones Tomcat 6.0.x, 7.0.x, 8.0.x, 8.5.x y 9.0.x son compatibles con el complemento. Asegúrese de no mezclar bibliotecas Tomcat de diferentes versiones.
Tomcat 6.0.x:
repositories {
mavenCentral()
}
dependencies {
def tomcatVersion = ' 6.0.51 '
tomcat " org.apache.tomcat:catalina: ${ tomcatVersion } " ,
" org.apache.tomcat:coyote: ${ tomcatVersion } " ,
" org.apache.tomcat:jasper: ${ tomcatVersion } "
}Tomcat 7.0.x:
repositories {
mavenCentral()
}
dependencies {
def tomcatVersion = ' 7.0.76 '
tomcat " org.apache.tomcat.embed:tomcat-embed-core: ${ tomcatVersion } " ,
" org.apache.tomcat.embed:tomcat-embed-logging-juli: ${ tomcatVersion } " ,
" org.apache.tomcat.embed:tomcat-embed-jasper: ${ tomcatVersion } "
}Tomcat 8.0.x:
repositories {
mavenCentral()
}
dependencies {
def tomcatVersion = ' 8.0.42 '
tomcat " org.apache.tomcat.embed:tomcat-embed-core: ${ tomcatVersion } " ,
" org.apache.tomcat.embed:tomcat-embed-logging-juli: ${ tomcatVersion } " ,
" org.apache.tomcat.embed:tomcat-embed-jasper: ${ tomcatVersion } "
}Tomcat 8.5.x:
Tenga en cuenta que la dependencia tomcat-embed-logging-juli solo se requiere para habilitar el registro de contenedores a través de Log4j 1.x (que ya no es compatible con la comunidad log4j). LOG4J 2.X se puede usar para el registro de contenedores sin declarar ninguna biblioteca adicional.
repositories {
mavenCentral()
}
dependencies {
def tomcatVersion = ' 8.5.16 '
tomcat " org.apache.tomcat.embed:tomcat-embed-core: ${ tomcatVersion } " ,
" org.apache.tomcat.embed:tomcat-embed-logging-juli:8.5.2 " ,
" org.apache.tomcat.embed:tomcat-embed-jasper: ${ tomcatVersion } "
}
tomcat {
httpProtocol = ' org.apache.coyote.http11.Http11Nio2Protocol '
ajpProtocol = ' org.apache.coyote.ajp.AjpNio2Protocol '
}Tomcat 9.0.x:
Tenga en cuenta que la dependencia tomcat-embed-logging-juli solo se requiere para habilitar el registro de contenedores a través de Log4j 1.x (que ya no es compatible con la comunidad log4j). LOG4J 2.X se puede usar para el registro de contenedores sin declarar ninguna biblioteca adicional.
repositories {
mavenCentral()
}
dependencies {
def tomcatVersion = ' 9.0.1 '
tomcat " org.apache.tomcat.embed:tomcat-embed-core: ${ tomcatVersion } " ,
" org.apache.tomcat.embed:tomcat-embed-logging-juli:9.0.0.M6 " ,
" org.apache.tomcat.embed:tomcat-embed-jasper: ${ tomcatVersion } "
}
tomcat {
httpProtocol = ' org.apache.coyote.http11.Http11Nio2Protocol '
ajpProtocol = ' org.apache.coyote.ajp.AjpNio2Protocol '
} El complemento com.bmuschko.tomcat prefines las siguientes tareas fuera de la caja:
| Nombre de la tarea | Depende de | Tipo | Descripción |
|---|---|---|---|
| tomcatrun | - | Tomcatrun | Inicia una instancia de Tomcat e implementa la aplicación web explotada. |
| tomcatrunwar | - | Tomcatrunwar | Inicia una instancia de Tomcat y despliega la guerra. |
| Tomcatstop | - | Tomcatstop | Detiene la instancia de Tomcat. |
| tomcatjasper | - | Tomcatjasper | Ejecuta el compilador JSP y convierte las páginas JSP en fuente Java usando Jasper. |
El complemento TomCat utiliza el mismo diseño que el complemento de guerra.
El complemento TomCat expone las siguientes propiedades a través de la extensión llamada tomcat :
httpPort : el puerto TCP en el que Tomcat debe escuchar las solicitudes HTTP (predeterminadas a 8080 ).httpsPort : el puerto TCP en el que Tomcat debe escuchar las solicitudes HTTPS (por defecto es 8443 ).ajpPort : el puerto TCP en el que Tomcat debe escuchar las solicitudes de AJP (predeterminados a 8009 ).stopPort : el puerto TCP en el que Tomcat debe escuchar las solicitudes de administración (predeterminados a 8081 ).stopKey : la clave para pasar a TomCat al solicitar que se detenga (por defecto es null ).contextPath : la ruta de contexto de URL bajo la cual se registrará la aplicación web (predeterminada al nombre de la guerra).enableSSL : determina si el conector HTTPS debe ser creado (predeterminado a false ).daemon : especifica si el servidor Tomcat debe ejecutarse en segundo plano. Cuando es cierto, esta tarea se completa tan pronto como el servidor ha comenzado. Cuando se falsa, esta tarea se bloquea hasta que el servidor Tomcat se detiene (predeterminado es false ).keystoreFile : el archivo del almacén de claves que se utilizará para SSL, si está habilitado (de forma predeterminada, se generará un almacén de claves).httpProtocol : el nombre de la clase del controlador del protocolo HTTP que se utilizará (predeterminado se encuentra en org.apache.coyote.http11.Http11Protocol ).httpsProtocol : el nombre de la clase del controlador del protocolo HTTPS que se utilizará (predeterminado se encuentra en org.apache.coyote.http11.Http11Protocol ).ajpProtocol : el nombre de la clase del controlador del protocolo AJP que se utilizará (predeterminado se encuentra en org.apache.coyote.ajp.AjpProtocol ).users : Lista de usuarios con username , password y roles . Se utiliza para configurar TomCat con la autenticación básica con estos usuarios. El siguiente código de ejemplo muestra cómo cambiar los puertos HTTP/HTTPS predeterminados. Para habilitar SSL, establecemos la propiedad enableSSL en true . Se puede acceder a la aplicación web en la sample-app ruta de contexto.
tomcat {
httpPort = 8090
httpsPort = 8091
enableSSL = true
contextPath = ' sample-app '
users {
user {
username = ' user1 '
password = ' 123456 '
roles = [ ' developers ' , ' admin ' ]
}
user {
username = ' user2 '
password = ' abcdef '
roles = [ ' manager ' ]
}
}
}Además, puede establecer las siguientes propiedades de tarea opcional:
contextPath : la ruta de contexto de URL en la que se registrará su aplicación web (predeterminada al nombre de guerra).webDefaultXml : el Web.xml predeterminado. Si no se define, se configurará una instancia de org.apache.catalina.servlets.DefaultServlet y org.apache.jasper.servlet.JspServlet .additionalRuntimeResources : define frascos o directorios de tiempo de ejecución adicionales que no proporcionan la aplicación web.URIEncoding : Especifica la codificación de caracteres utilizada para decodificar los bytes URI por el conector HTTP (predeterminado es UTF-8 ).daemon : especifica si el servidor Tomcat debe ejecutarse en segundo plano. Cuando es cierto, esta tarea se completa tan pronto como el servidor ha comenzado. Cuando se falsa, esta tarea se bloquea hasta que el servidor Tomcat se detiene (predeterminado es false ).configFile : la ruta al archivo XML de contexto TomCat (predeterminado se encuentra a src/main/webapp/META-INF/context.xml para tomcatRun , predeterminado a META-INF/context.xml dentro de la guerra para tomcatRunWar ).outputFile : el archivo para escribir mensajes de registro Tomcat. Si el archivo ya existe, se agregarán nuevos mensajes.reloadable : Fuerza de escaneo de contexto si no usa un archivo de contexto (predeterminado es true ).keystorePass : la contraseña del almacén de claves para usar para SSL, si está habilitado.truststoreFile : el archivo TrustStore para usar para SSL, si está habilitado.truststorePass : la contraseña de confianza para usar para SSL, si está habilitado.clientAuth : la configuración de ClientAuth para usar, los valores pueden ser: true , false o want (predeterminado a false ). Nota: keystoreFile y truststoreFile requieren una instancia de un archivo de objeto File , por ejemplo, file("/path/my.file")
En el siguiente código de ejemplo, declaramos un archivo de contexto personalizado para la tarea tomcatRun .
tomcatRun . configFile = file( ' context.xml ' ) Para configurar la tarea del compilador Jasper, puede elegir establecer las siguientes propiedades dentro del cierre jasper de la extensión tomcat :
validateXml : determina si web.xml debe validarse (predeterminado a null ).validateTld : determina si web.xml debe validarse (predeterminado a null ).uriroot : el directorio raíz de la aplicación web (predeterminada se encuentra a src/main/webapp ).webXmlFragment : el archivo de fragmento XML web generado para ser referenciado por su archivo web.xml .addWebXmlMappings : agregue automáticamente el fragmento XML web generado al archivo web.xml . PRECAUCIÓN: Esto modificará el archivo web.xml en el proyecto, no en el directorio de compilación.outputDir : el directorio de salida Los JSP compilados terminarán (predeterminados para build/jasper ).classdebuginfo : si el archivo de clase se compilará con la información de depuración (predeterminada es true ).compiler : qué compilador de hormiga debe usar para compilar las páginas JSP. Consulte la documentación de Ant para obtener más información. Si el valor no está configurado, entonces el compilador JDT Java Eclipse predeterminado se usará en lugar de usar ANT. Sin valor predeterminado.compilerSourceVM : ¿Con qué versión JDK son los archivos de origen compatibles (predeterminados a 1.6 )?compilerTargetVM : con qué versión JDK son los archivos generados compatibles (predeterminado es 1.6 ).poolingEnabled : determina si la agrupación de controladores de etiquetas está habilitada. Esta es una opción de compilación. No alterará el comportamiento de los JSP que ya se han compilado (predeterminado es true ).errorOnUseBeanInvalidClassAttribute : Si Jasper emite un error cuando el valor del atributo de clase en una acción de UseBean no es una clase de bean válida (predeterminada es true ).genStringAsCharArray : si las cadenas de texto se generan como matrices de carbón, para mejorar el rendimiento en algunos casos (predeterminados a false ).ieClassId : El valor de ID de clase se enviará a Internet Explorer cuando use <jsp:plugin> etiquetas (predeterminados a clsid:8AD9C840-044E-11D1-B3E9-00805F499D93 ).javaEncoding : la codificación del archivo Java para usar para generar archivos de origen Java (predeterminado se encuentra en UTF8 ).trimSpaces : deben recortarse los espacios blancos en el texto de la plantilla entre acciones o directivas (el valor predeterminado en TrimSpaces.TRUE ).xpoweredBy : determina si el encabezado de respuesta X-Powered es agregado por Servlet generado (predeterminado es false ).tomcat {
jasper {
validateXml = true
webXmlFragment = file( " $w ebAppDir /WEB-INF/generated_web.xml " )
outputDir = file( " $w ebAppDir /WEB-INF/src " )
}
}Recibo una excepción de compilación al llamar a un JSP. ¿Hay algo que me falta?
La excepción que puede ver es probablemente similar a esta: org.apache.jasper.JasperException: Unable to compile class for JSP . Tomcat 7.x y 8.x requieren que tenga Eclipse ECJ 3.6.X en su classpath. Sin embargo, esta versión de la dependencia no existe en Maven Central. Tendrá que descargar esa dependencia y ponerla en su propio repositorio o definir un repositorio en su disco local donde pueda dejarla. Aquí hay un ejemplo:
repositories {
flatDir name : ' localRepository ' , dirs : ' lib '
} ¿Por qué obtengo un java.lang.ClassCastException en javax.servlet.Servlet ?
Tomcat es muy sensible a tener múltiples versiones de las dependencias javax.servlet:servlet-api y javax.servlet:jsp-api en su classpath. Por defecto, ya se atraen como dependencias transitivas de las bibliotecas Tomcat integradas. La excepción que puede ver se parece a esta:
java.lang.ClassCastException: org.springframework.web.servlet.DispatcherServlet cannot be cast to javax.servlet.Servlet
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1062)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1010)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4935)
at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5262)
at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5257)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Para solucionar esto, asegúrese de definir sus dependencias del módulo JSP y Servlet con el alcance providedCompile como este:
providedCompile ' javax.servlet:servlet-api:2.5 ' ,
' javax.servlet:jsp-api:2.0 '¿Cómo debo depurar remotamente mi Tomcat iniciado por el complemento?
Si desea poder depurar su aplicación de forma remota, debe establecer las siguientes opciones de JVM en su variable de entorno GRADLE_OPTS antes de iniciar el contenedor. El número de puerto que elija depende de usted.
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
Tomcat luego escuchará en el puerto especificado para conexiones de depuración remota entrantes. Al iniciar el contenedor, debería ver el siguiente mensaje:
Listening for transport dt_socket at address: 5005
Verifique su documentación IDE sobre cómo configurar la conexión al puerto de depuración remota.
Mi contenedor Tomcat necesita usar una fuente de datos JNDI. ¿Cómo configuro mi proyecto?
En primer lugar, debe asegurarse de declarar la dependencia del grupo de conexión utilizando la configuración tomcat .
Tomcat 6.0.x:
def tomcatVersion = ' 6.0.35 '
tomcat " org.apache.tomcat:dbcp: ${ tomcatVersion } "Ver coordenadas en Maven Central para más detalles.
Versiones posteriores:
def tomcatVersion = ' 9.0.8 '
tomcat " org.apache.tomcat:tomcat-dbcp: ${ tomcatVersion } "Ver coordenadas en Maven Central para más detalles.
Si decide ir con la configuración predeterminada, coloque su context.xml en el directorio src/main/webapp/META-INF . Para establecer una ubicación personalizada, puede usar la propiedad de convención configFile . Aquí hay un ejemplo sobre cómo establecerlo para las tareas tomcatRun y tomcatRunWar .
[tomcatRun, tomcatRunWar] * . configFile = file( ' context.xml ' )Consulte la documentación de Tomcat para obtener una lista de atributos de contexto. El siguiente ejemplo muestra cómo configurar una fuente de datos MySQL JNDI.
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< Context >
< Resource name = " jdbc/mydatabase "
auth = " Container "
type = " javax.sql.DataSource "
username = " superuser "
password = " secretpasswd "
driverClassName = " com.mysql.jdbc.Driver "
url = " jdbc:mysql://localhost:3306/mydb "
validationQuery = " select 1 "
maxActive = " 10 "
maxIdle = " 4 " />
</ Context >¿Cómo uso la implementación del código caliente con el complemento?
El complemento proporciona soporte listo para usar para intercambiar código de byte a través de la propiedad reloadable . Por defecto, esta opción se produce para que no necesite ningún cambio de configuración adicional. Todo lo que necesita hacer es tener una instancia en ejecución del contenedor iniciado por tomcatRun . Encuentre su editor favorito, cambie un archivo fuente de producción, guárdelo y vuelva a compilar sus fuentes en otro terminal a través de gradle compileJava . Después de un par de segundos, el contexto se vuelve a cargar y debe ver el comportamiento reflejado en la ventana terminal que ejecuta el contenedor:
Reloading Context with name [/myapp] has started
Reloading Context with name [/myapp] is completed
Alternativamente, puede usar otras tecnologías de intercambio de códigos de bytes comerciales. La configuración suele ser específica del producto. Consulte la documentación del producto sobre cómo configurarlo para su proyecto. La siguiente sección describe cómo configurar Gradle y el complemento con Jrebel. En primer lugar, descargue Jrebel, instálelo en su máquina y configure la licencia. Para decirle a JRebel qué directorio escanear el código BYTE modificado, debe crear un archivo Rebel.xml. En su módulo web, coloque el archivo en build/classes/main para que el complemento TomCat pueda cargarlo. Para crear la configuración del archivo, el complemento Gradle JRebel es útil. No es necesario usar el complemento. También puede decidir crear la configuración a mano. Tenga en cuenta que gradle clean eliminará el archivo. Para configurar Jrebel en un escenario de proyecto múltiple, consulte la documentación. El siguiente fragmento de código muestra un ejemplo de ejemplo rebel.xml .
<? xml version = " 1.0 " encoding = " UTF-8 " ?>
< application xmlns : xsi = " http://www.w3.org/2001/XMLSchema-instance " xmlns = " http://www.zeroturnaround.com "
xsi : schemaLocation = " http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd " >
< classpath >
< dir name = " /Users/ben/dev/projects/mywebproject/build/classes/main " >
</ dir >
</ classpath >
< web >
< link target = " / " >
< dir name = " /Users/ben/dev/projects/mywebproject/src/main/webapp " >
</ dir >
</ link >
</ web >
</ application > Edite su script de inicio de Gradle y agregue la siguiente línea para decirle a Gradle que use el agente Jrebel. Asegúrese de establecer la variable de entorno REBEL_HOME que apunta a su directorio de instalación de Jrebel.
JAVA_OPTS="-javaagent:$REBEL_HOME/jrebel.jar $JAVA_OPTS"
Al inicio de su módulo web utilizando gradle tomcatRun debe ver información sobre la licencia de Jrebel que se está utilizando y los directorios que se están escaneando en busca de cambios. Para nuestro ejemplo del archivo rebel.xml , se vería así:
JRebel: Directory '/Users/ben/dev/projects/mywebproject/build/classes/main' will be monitored for changes.
JRebel: Directory '/Users/ben/dev/projects/mywebproject/src/main/webapp' will be monitored for changes.
Si un archivo ha sido recompinado, Jrebel indica esto escribiéndolo en la consola como esta:
JRebel: Reloading class 'de.muschko.web.controller.TestController'.
En la necesidad de ejecutar pruebas de integración en contenedores como parte de mi construcción. ¿Qué hay que hacer?
Por lo general, las pruebas de unidad y de integración se mantienen separadas por la convención. Una convención podría ser nombrar los archivos de la fuente de prueba de manera diferente, por ejemplo, las pruebas de integración siempre terminan con el sufijo IntegrationTest , los archivos de prueba unitarios terminan con Test . Al hacerlo, puedes ejecutarlos por separado. Para ejecutar las pruebas de integración, querrá ejecutar la tarea Tomcat como hilo de demonio y apagarlo una vez que se realicen sus pruebas. El siguiente ejemplo demuestra cómo configurar una tarea de Gradle que proporcione esta funcionalidad. Por supuesto, esta es solo una forma de hacerlo. El siguiente ejemplo requiere gradle> = 1.7:
apply plugin : ' com.bmuschko.tomcat-base '
ext {
tomcatStopPort = 8081
tomcatStopKey = ' stopKey '
}
task integrationTomcatRun( type : com.bmuschko.gradle.tomcat.tasks.TomcatRun ) {
stopPort = tomcatStopPort
stopKey = tomcatStopKey
daemon = true
}
task integrationTomcatStop( type : com.bmuschko.gradle.tomcat.tasks.TomcatStop ) {
stopPort = tomcatStopPort
stopKey = tomcatStopKey
}
task integrationTest( type : Test ) {
include ' **/*IntegrationTest.* '
dependsOn integrationTomcatRun
finalizedBy integrationTomcatStop
}
test {
exclude ' **/*IntegrationTest.* '
}¿Cómo agrego archivos jar o directorios que no forman parte del código fuente de mi aplicación web?
Cada tarea de tipo AbstractTomcatRun expone una propiedad llamada additionalRuntimeResources que se utiliza para mezclar con la clase de tiempo de ejecución de la aplicación web.
[tomcatRun, tomcatRunWar] . each { task ->
task . additionalRuntimeResources << file( ' /Users/bmuschko/config/props ' )
task . additionalRuntimeResources << file( ' /Users/bmuschko/ext/jars/my.jar ' )
}