Dropwizard Internals¶
You already read through the whole Dropwizard documentation? Congrats! Then you are ready to have a look into some nitty-gritty details of Dropwizard.
Startup Sequence¶
Application<T extends Configuration>
is the “Main” class of a Dropwizard Application.
application.run(args)
is the first method to be called on startup - Here is a simplified code snippet of its implementation:
public void run(String... arguments) throws Exception {
final Bootstrap<T> bootstrap = new Bootstrap<>(this);
bootstrap.addCommand(new ServerCommand<>(this));
bootstrap.addCommand(new CheckCommand<>(this));
initialize(bootstrap); // -- implemented by you; it should call:
// 1. add bundles (typically being used)
// 2. add commands (if any)
// Should be called after `initialize` to give an opportunity to set a custom metric registry
bootstrap.registerMetrics(); // start tracking some default jvm params…
// for each cmd, configure parser w/ cmd
final Cli cli = new Cli(new JarLocation(getClass()), bootstrap, our, err)
cli.run(arguments);
}
Bootstrap
is the pre-start (temp) application environment, containing everything required to bootstrap a Dropwizard command. Here is a simplified code snippet to illustrate its structure:
Bootstrap(application: Application<T>) {
this.application = application;
this.objectMapper = Jackson.newObjectMapper();
this.bundles = new ArrayList<>();
this.configuredBundles = new ArrayList<>();
this.commands = new ArrayList<>();
this.validatorFactory = Validators.newValidatorFactory();
this.metricRegistry = new MetricRegistry();
this.classLoader = Thread.currentThread().getContextClassLoader();
this.configurationFactory = new DefaultConfigurationFactoryFactory<>();
this.healthCheckRegistry = new HealthCheckRegistry();
}
Environment
is a longer-lived object, holding Dropwizard’s Environment (not env. Such as dev or prod). It holds a similar, but somewhat different set of properties than the Bootstrap object - here is a simplified code snippet to illustrate that:
Environment (...) {
// from bootstrap
this.objectMapper = ...
this.classLoader = ...
this.metricRegistry = ...
this.healthCheckRegistry = ...
this.validator = bootstrap.getValidatorFactory().getValidator()
// extra:
this.bundles = new ArrayList<>();
this.configuredBundles = new ArrayList<>();
// sub-environments:
this.servletEnvironment = ... // -- exposed via the servlets() method
this.jerseyEnvironment = ... // -- exposed via the jersey() method
this.adminEnvironment = ... // -- exposed via the admin() method
}
A Dropwizard Bundle
is a reusable group of functionality (sometimes provided by the Dropwizard project itself), used to define blocks of an application’s behavior.
For example, AssetBundle
from the dropwizard-assets module provides a simple way to serve static assets from your application’s src/main/resources/assets directory as files available from /assets/* (or any other path) in your application.
A ConfiguredBundle
is a bundle that requires a configuration provided by the Configuration
object (implementing a relevant interface)
Properties such as database connection details should not be stored on the Environment; that is what your Configuration .yml file is for. Each logical environment (dev/test/staging/prod) - would have its own Configuration .yml - reflecting the differences between different “server environments”.
Commands¶
Command
objects are basic actions, which Dropwizard runs based on the arguments provided on the command line. The built-in server
command, for example, spins up an HTTP server and runs your application. Each Command subclass has a name and a set of command line options which Dropwizard will use to parse the given command line arguments.
The check
command parses and validates the application’s configuration.
If you will check again the first code snippet in this document - you will see creating these two commands, is the first step in the bootstrapping process.
Another important command is db
- allowing executing various db actions, see Dropwizard Migrations
Similar to ConfiguredBundle
, some commands require access to configuration parameters and should extend the ConfiguredCommand
class, using your application’s Configuration
class as its type parameter.
The CLI class¶
Let us begin with a simplified version of the constructor:
public Cli(location : JarLocation, bootstrap : Bootstrap<?>,
stdOut: OutputStream, stdErr: OutputStream) {
this.stdout = stdOut; this.stdErr = stdErr;
this.commands = new TreeMap<>();
this.parser = buildParser(location);
this.bootstrap = bootstrap;
for (command in bootstrap.commands) {
addCommand(command)
}
}
Cli is the command-line runner for Dropwizard application. Initializing, and then running it - is the last step of the Bootstrapping process.
Run would just handle commandline args (–help, –version) or runs the configured commands.
E.g. - When running the server
command:
java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml
Just note the two basic commands are built of a parent, and a sub-class:
class CheckCommand<T extends Configuration> extends ConfiguredCommand<T>
class ServerCommand<T extends Configuration> extends EnvironmentCommand<T>
The order of operations is therefore:
- Parse cmdline args, determine sub-command.
- Run
ConfiguredCommand
, which get a parameter with the location of a YAML configuration file - parses and validates it. CheckCommand.run()
runs next, and does almost nothing: it logs"Configuration is OK"
- Run
EnvironmentCommand
:
- Create
Environment
- Calls
bootstrap.run(cfg, env)
- run bundles with config. & env.- Bundles run in FIFO order.
- Calls
application.run(cfg, env)
– implemented by you
- Now,
ServerCommand.run()
runs
- Calls
serverFactory.build(environment)
- to configure Jetty and Jersey, with all relevant Dropwizard modules.- Starts Jetty.
Jetty Lifecycle¶
If you have a component of your app that needs to know when Jetty is going to start, you can implement Managed as described in the Dropwizard docs.
If you have a component that needs to be signaled that Jetty has started (this happens after all Managed objects’ start() methods are called), you can register with the env’s lifecycle like:
env.lifecycle().addServerLifecycleListener(new ServerLifecycleListener() {
@Override
public void serverStarted(Server server) {
/// ... do things here ....
}
});