06 - Tomcat: tradicional y embebido
Tomcat es un contenedor de servlets: gestiona el ciclo de vida de los servlets y filtros, atiende las conexiones y reparte cada petición en un hilo de su pool. Es la versión “de verdad” del servidor que se construyó en los temas anteriores, y se usa de dos maneras: instalado aparte (la manera tradicional) o embebido dentro de la aplicación (la habitual hoy).
1. Qué hace
| Capa | Cómo la resuelve Tomcat |
|---|---|
| Sockets y protocolo HTTP | Conector HTTP en un puerto (por defecto 8080) |
| Concurrencia | Pool de hilos worker (http-nio-8080-exec-N, tema 05) |
| Enrutado | Cada ruta (@WebServlet, @WebFilter) a su componente |
| Ciclo de vida | init/destroy de servlets y filtros; listeners al arrancar y parar la webapp |
| Recursos | Archivos estáticos, errores HTTP, sesiones (no se usan aquí) |
Tomcat ejecuta exactamente el modelo de los temas anteriores: acepta conexiones, las reparte en hilos del pool y delega cada petición en un servlet a través de la cadena de filtros. Lo que cambia según el modo de uso es quién instala y arranca ese servidor.
2. Hilos de Tomcat
El conector de Tomcat es el pool del tema 05 hecho servidor: acepta las conexiones y reparte cada petición en un hilo worker libre del pool.
- El nombre del hilo lo delata en los logs:
http-nio-8080-exec-3es el worker 3 del pool. - Una petición en curso es un hilo ocupado; al responder, el hilo vuelve al pool y sirve a otro cliente.
- El pool tiene techo:
maxThreadsmarca el máximo de peticiones simultáneas; con más carga, las que no caben esperan en cola.minSpareThreadsdeja hilos creados de antemano. - La configuración va en
conf/server.xml(manera tradicional) o en las propiedades del embebido.
Las reglas de estado compartido del tema 05 aplican tal cual: servlets y filtros atienden muchas peticiones con una sola instancia.
ThreadLocal para una petición sigue ahí cuando ese mismo hilo atiende la siguiente, si nadie lo limpia. Con pool de hilos, limpiar el ThreadLocal forma parte de terminar la petición.
3. Listeners
Los listeners son el tercer tipo de componente del contenedor, junto a servlets y filtros: en lugar de atender peticiones, añaden código al ciclo de vida de la webapp:
@WebListener
public class AppListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
// al desplegar la webapp: preparar recursos compartidos
}
@Override
public void contextDestroyed(ServletContextEvent event) {
// al pararla: liberarlos
}
}
contextInitialized: se ejecuta una vez al desplegar la aplicación; es el sitio para preparar lo que servirá a servlets y filtros: abrir el pool de conexiones a la base de datos, leer la configuración…contextDestroyed: se ejecuta al parar la aplicación; libera esos recursos.- Funciona igual en los dos modos: el contenedor registra el listener en el arranque, sea Tomcat instalado aparte o embebido.
Con servlets, filtros (tema 04) y listeners, está completo el cuadro de componentes que un contenedor gestiona.
4. Estructura de una webapp
La unidad de despliegue es la webapp, una carpeta con estructura fija:
miapp/ ├── WEB-INF/ │ ├── web.xml (configuración, opcional con anotaciones) │ ├── classes/ (clases compiladas) │ └── lib/ (JARs de dependencias) ├── index.html └── ...
- El contenido fuera de
WEB-INFse sirve como archivos estáticos (HTML, CSS, JS). WEB-INFno es accesible por HTTP: contiene código y configuración.- La aplicación se empaqueta como
.war(*Web ARchive*) para desplegarla.
5. Anotaciones frente a web.xml
Las rutas se declaran con anotaciones:
@WebServlet("/books")
public class BookServlet extends HttpServlet { /* ... */ }
@WebFilter("/*")
public class TokenFilter implements Filter { /* ... */ }
O en web.xml con el mismo resultado:
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" version="6.0">
<servlet>
<servlet-name>bookServlet</servlet-name>
<servlet-class>com.example.BookServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bookServlet</servlet-name>
<url-pattern>/books</url-pattern>
</servlet-mapping>
</web-app>
La combinación habitual: anotaciones para lo simple, web.xml cuando la configuración cambia por entorno.
6. Manera tradicional: servidor independiente
En el modo tradicional, Tomcat se instala aparte y las aplicaciones se despliegan en él:
apache-tomcat/ ├── bin/ scripts de arranque y parada (startup.sh, shutdown.sh) ├── conf/ configuración; server.xml fija el puerto (por defecto 8080) ├── logs/ registro del servidor (catalina.out) ├── webapps/ aplicaciones desplegadas └── ...
- Se copia el
.warenwebappsy Tomcat lo despliega en su context path:miapp.warqueda publicado enhttp://localhost:8080/miapp. - El servidor se arranca y se para con los scripts de
bin; los logs quedan enlogs. - Un mismo Tomcat puede servir varias webapps, con un pool de hilos compartido.
Es el modo clásico de producción —y el que sigue usándose cuando varias aplicaciones comparten servidor—, pero obliga a instalar y versionar el servidor por separado de la aplicación.
7. Tomcat embebido
En el modo embebido, la aplicación incluye el servidor como una dependencia más y lo arranca desde su propio main:
public class App {
public static void main(String[] args) throws Exception {
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
Context context = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
Tomcat.addServlet(context, "books", new BookServlet());
context.addServletMappingDecoded("/books", "books");
tomcat.start(); // conector, pool y ciclo de vida
tomcat.getServer().await(); // el main queda a la espera
}
}
No hay webapps ni .war: el jar de la aplicación es el servidor. Arrancar la aplicación es arrancar Tomcat.
Así funciona Spring Boot: la aplicación declara el arranque y el contenedor viene dentro. En 2.º DAW se usará de esta forma; el main de un proyecto Spring Boot levanta un Tomcat embebido idéntico al de este tema.
8. Tradicional frente a embebido
| Tradicional | Embebido | |
|---|---|---|
| Instalación | Servidor compartido, se instala aparte | El servidor viene dentro de la app |
| Despliegue | Copiar el .war en webapps | Ejecutar el jar de la aplicación |
| Configuración | conf/server.xml del servidor | Propiedades de la aplicación |
| Escenarios | Varias apps en un mismo servidor | Una app, un servidor (modelo dominante hoy) |
jar.