Web Application Deployment

When using the Jetty server libraries in your code, web applications are typically assembled by composing the required Handlers, as explained in this section.

When the Server instance is started, web applications are also started; there typically is no deployer component that can deploy web applications after the Server instance is started.

The deployer component is the key component to deploy web applications when using Jetty as a standalone server, and it is detailed here.

However, it is possible to use the Jetty server libraries in your code with the deployer component, so that you can deploy web applications after the Server instance is started.

The Maven artifact coordinates are:

<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-deploy</artifactId>
  <version>12.1.4</version>
</dependency>

The main components to set up are:

  • A Deployer, by default org.eclipse.jetty.deploy.StandardDeployer. The deployer component is responsible for adding and removing a ContextHandler (or subclass) instance, that represents a web application, from the Handler tree, and is responsible for the lifecycle (starting and stopping) the ContextHandler.

  • A DeploymentScanner, that scans directories for files or directories that represent web applications. Typical web application files are *.war, *.properties and *.xml files. When a web application file or directory is added/updated/removed, DeploymentScanner creates or retrieves (depending on the event) the corresponding ContextHandler and calls the Deployer to deploy/redeploy/undeploy the web application.

Diagram

Each web application is deployed to a specific environment.

The environment allows you to specify environmental properties that will be available to all web applications, as well as a ClassLoader that loads classes that are specific to the environment.

Furthermore, the environment determines how the web application file should be interpreted: if it is a directory, whether it should be interpreted as a Jetty Static web application, or as a Jetty Core web application, or as a Jakarta EE exploded *.war.

By default, there are no environments; you must always create at least one, depending on the type of deployment you want for your web applications.

Simple Deployer Setup

The simplest deployer setup is when you deploy a web application via Jetty context XML file:

Server server = new Server();

// ContextHandlerCollection is required by the deployer.
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);

// Optional, shows the contexts deployed on the Server.
server.setDefaultHandler(new DefaultHandler());

// Create the deployer.
Deployer deployer = new StandardDeployer(contexts);

// Create the DeploymentScanner to monitor the webapps directory.
DeploymentScanner scanner = new DeploymentScanner(server, deployer);
scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
// Link the lifecycle of the DeploymentScanner to the Server.
server.addBean(scanner);

// Create an environment, with the name of your choice,
// and no extra class-path or module-path.
EnvironmentBuilder envBuilder = new EnvironmentBuilder("simple");
Environment environment = envBuilder.build();

// Tell the DeploymentScanner about the environment
// it should use to deploy web applications.
scanner.configureEnvironment(environment.getName());

server.start();

With this simple setup, you can only deploy Jetty context XML files. In the Jetty context XML files, you can only reference classes that you have in the class-path or module-path, for example:

acme-webapp.xml
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
  <Set name="contextPath">/acme</Set>
  <Set name="handler">
    <New class="com.acme.WebAppHandler" /> (1)
  </Set>
</Configure>
1 This class must be in the class-path or module-path.
Do not be tempted to use this simple setup to deploy Jetty Core web applications, Jetty Static web applications, or Jakarta web applications; their setup is described their respective sections below.

Jetty Static Deployer Setup

For Jetty Static web applications, the setup is the following:

Server server = new Server();

// ContextHandlerCollection is required by the deployer.
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);

// Optional, shows the contexts deployed on the Server.
server.setDefaultHandler(new DefaultHandler());

// Create the deployer.
Deployer deployer = new StandardDeployer(contexts);

// Create the DeploymentScanner to monitor the webapps directory.
DeploymentScanner scanner = new DeploymentScanner(server, deployer);
scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
// Link the lifecycle of the DeploymentScanner to the Server.
server.addBean(scanner);

// Create the static environment.
EnvironmentBuilder envBuilder = new EnvironmentBuilder("static");
envBuilder.addClassPath("/path/to/jetty-staticapp-12.1.4.jar"); (1)
Environment environment = envBuilder.build();

// Tell the DeploymentScanner about the environment, and configure it for deployment.
DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName()); (2)
envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.staticapp.StaticAppContext");

server.start();
1 The environment is configured with its own class-path.
2 Jetty Static web applications use StaticAppContext as their ContextHandler, so web application directories are interpreted as having the Jetty Static web application format.

Your Jetty Static web application is a directory, for example acme-asset/, under /path/to/webapps/:

/path/to/webapps/
└── acme-assets/
    ├── css/
    │   └── styles.css
    └── index.html

Jetty Core Deployer Setup

For Jetty Core web applications, the setup is the following:

Server server = new Server();

// ContextHandlerCollection is required by the deployer.
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);

// Optional, shows the contexts deployed on the Server.
server.setDefaultHandler(new DefaultHandler());

// Create the deployer.
Deployer deployer = new StandardDeployer(contexts);

// Create the DeploymentScanner to monitor the webapps directory.
DeploymentScanner scanner = new DeploymentScanner(server, deployer);
scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
// Link the lifecycle of the DeploymentScanner to the Server.
server.addBean(scanner);

// Create the core environment.
EnvironmentBuilder envBuilder = new EnvironmentBuilder("core");
envBuilder.addClassPath("/path/to/jetty-coreapp-12.1.4.jar"); (1)
Environment environment = envBuilder.build();

// Tell the DeploymentScanner about the environment, and configure it for deployment.
DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName()); (2)
envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.coreapp.CoreAppContext");

server.start();
1 The environment is configured with its own class-path.
2 Jetty Core web applications use CoreAppContext as their ContextHandler, so web application directories are interpreted as having the Jetty Core web application format.

Your Jetty Core web application is a directory, for example acme-core-app/ under /path/to/webapps/:

/path/to/webapps/
└── acme-core-app/
    ├── static         # Static files are served from this directory.
    │   └── favicon.ico
    ├── classes        # Where web application Java classes reside.
    │   └── com
    │       └── acme
    │           └── AcmeHandler.class
    ├── lib            # Where web application Java libraries reside.
    │   └── acme-util.jar
    └── jetty-web.xml  # Web application specific configuration.

With this setup you have the following class loader hierarchy, with the standard parent first model for class loading:

System ClassLoader                 # jetty-server-12.1.4.jar, etc.
└── Environment ClassLoader        # jetty-coreapp-12.1.4.jar
    └── Jetty Core App ClassLoader # acme-core-app/classes/:acme-core-app/lib/acme-util.jar

Jakarta Deployer Setup

For Jakarta web applications, the setup is the following:

Server server = new Server();

// ContextHandlerCollection is required by the deployer.
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);

// Optional, shows the contexts deployed on the Server.
server.setDefaultHandler(new DefaultHandler());

// Create the deployer.
Deployer deployer = new StandardDeployer(contexts);

// Create the DeploymentScanner to monitor the webapps directory.
DeploymentScanner scanner = new DeploymentScanner(server, deployer);
scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
// Link the lifecycle of the DeploymentScanner to the Server.
server.addBean(scanner);

// Create the ee11 environment.
EnvironmentBuilder envBuilder = new EnvironmentBuilder("ee11");
envBuilder.addClassPath("/path/to/jakarta.servlet-api-6.1.0.jar"); (1)
envBuilder.addClassPath("/path/to/jetty-ee11-servlet-12.1.4.jar");
envBuilder.addClassPath("/path/to/jetty-ee11-webapp-12.1.4.jar");
Environment environment = envBuilder.build();

// Tell the DeploymentScanner about the environment, and configure it for deployment.
DeploymentScanner.EnvironmentConfig envConfig = scanner.configureEnvironment(environment.getName());
envConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.ee11.webapp.WebAppContext"); (2)
envConfig.setDefaultsDescriptor("/path/to/ee11-default-web.xml"); (3)
// Other relevant Jakarta environment configurations.

server.start();
1 The environment is configured with its own class-path, that includes the Servlet API *.jar and the Jetty implementation `*.jar`s of the Servlet APIs.
2 Jakarta web applications use WebAppContext as their ContextHandler, so web application *.war files or directories are interpreted as having the Jakarta web application format.

Your Jakarta web application is a *.war file, for example acme.war under /path/to/webapps/:

/path/to/webapps/
└── acme.war

With this setup you have the following class loader hierarchy, with the standard Jakarta web application first model for class loading:

System ClassLoader                  # jetty-server-12.1.4.jar: etc.
└── Environment ClassLoader         # jakarta.servlet-api-6.1.0.jar: etc.
    └── Jakarta Web App ClassLoader # acme.war!/WEB-INF/classes/:acme.war!/WEB-INF/lib/*.jar

Multiple Environments

If you need to deploy web applications to different environments, for example core and ee11, the setup is the following:

Server server = new Server();

// ContextHandlerCollection is required by the deployer.
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);

// Optional, shows the contexts deployed on the Server.
server.setDefaultHandler(new DefaultHandler());

// Create the deployer.
Deployer deployer = new StandardDeployer(contexts);

// Create the DeploymentScanner to monitor the webapps directory.
DeploymentScanner scanner = new DeploymentScanner(server, deployer);
scanner.setWebappsDirectories(List.of(Path.of("/path/to/webapps")));
// Link the lifecycle of the DeploymentScanner to the Server.
server.addBean(scanner);

// Create the core environment.
EnvironmentBuilder coreEnvBuilder = new EnvironmentBuilder("core");
coreEnvBuilder.addClassPath("/path/to/jetty-coreapp-12.1.4.jar");
Environment coreEnv = coreEnvBuilder.build();

// Create the ee11 environment.
EnvironmentBuilder jakartaEnvBuilder = new EnvironmentBuilder("ee11");
jakartaEnvBuilder.addClassPath("/path/to/jakarta.servlet-api-6.1.0.jar");
jakartaEnvBuilder.addClassPath("/path/to/jetty-ee11-servlet-12.1.4.jar");
jakartaEnvBuilder.addClassPath("/path/to/jetty-ee11-webapp-12.1.4.jar");
Environment jakartaEnv = jakartaEnvBuilder.build();

// Tell the DeploymentScanner about the environments, and configure them for deployment.

DeploymentScanner.EnvironmentConfig coreEnvConfig = scanner.configureEnvironment(coreEnv.getName());
coreEnvConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.coreapp.CoreAppContext");

DeploymentScanner.EnvironmentConfig jakartaEnvConfig = scanner.configureEnvironment(jakartaEnv.getName());
jakartaEnvConfig.setDefaultContextHandlerClassName("org.eclipse.jetty.ee11.webapp.WebAppContext");
jakartaEnvConfig.setDefaultsDescriptor("/path/to/ee11-default-web.xml");
// Other relevant Jakarta environment configurations.

server.start();

The class loader hierarchy is the following:

System ClassLoader
├── core Environment ClassLoader
│   └── Jetty Core App ClassLoader
└── ee11 Environment ClassLoader
    └── Jakarta Web App ClassLoader

With multiple environments, it is good practice to specify the web application *.properties file, as described in this section.