Dropwizard
Dropwizard straddles the line between being a library and a framework. Its goal is to provide performant, reliable implementations of everything a production-ready web application needs. Because this functionality is extracted into a reusable library, your application remains lean and focused, reducing both time-to-market and maintenance burdens.
Jetty for HTTP: Dropwizard projects have a main
method which spins up an HTTP server.
Jersey for REST. Write clean, testable classes which gracefully map HTTP requests to simple Java objects.
Jackson for JSON. Fast sophisticated object mapper, allowing you to export your domain models directly.
Metrics for metrics. Insight into your code’s behavior in your production environment.
Creating a Microservice
Sample:
https://github.com/dropwizard/dropwizard/tree/master/dropwizard-example
Step 1. Create using the Dropwizard archetype
https://github.com/dropwizard/dropwizard/tree/master/dropwizard-archetypes
Execute in command line: (Example: groupId: shkola, artifactId: api-base, package: com.mehrit-gi.shkola)
mvn archetype:generate -DarchetypeGroupId=io.dropwizard.archetypes -DarchetypeArtifactId=java-simple
-DarchetypeVersion=1.2.0
Output:
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: java-simple:1.2.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: shkola
[INFO] Parameter: artifactId, Value: api-base
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.mehrit-gi.shkola
[INFO] Parameter: packageInPathFormat, Value: com/mehrit-gi/shkola
[INFO] Parameter: package, Value: com.mehrit-gi.shkola
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: name, Value: shkola
[INFO] Parameter: groupId, Value: shkola
[INFO] Parameter: description, Value: null
[INFO] Parameter: shaded, Value: true
[INFO] Parameter: artifactId, Value: api-base
[INFO] Project created from Archetype in dir: C:\shkola\api\base\projects\api-base
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 04:07 min
[INFO] Finished at: 2017-10-27T15:08:56-05:00
[INFO] Final Memory: 16M/210M
[INFO] ------------------------------------------------------------------------
Add it to Bitbucket:
git clone https://[email protected]/mehritgi/api-base.git
cd api-base
echo "# My project's README" >> README.md
git add README.md
git commit -m "Initial commit"
git push -u origin master
If exists:
git remote add origin https://[email protected]/mehritgi/api-base.git
git push -u origin master
Step 2. Include dependencies in POM
In properties:
<properties>
<dropwizard.version>INSERT VERSION HERE</dropwizard.version>
</properties>
In dependencies:
<dependencies>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
<version>${dropwizard.version}</version>
</dependency>
</dependencies>
Step 3. Configuration Class
The YAML file containing configuration settings (<name>.yml)
template: Hello, %s!
defaultName: Stranger
Here. Parses the YAML file.
package com.example.helloworld;
import io.dropwizard.Configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;
public class HelloWorldConfiguration extends Configuration {
@NotEmpty
private String template;
@NotEmpty
private String defaultName = "Stranger";
@JsonProperty
public String getTemplate() {
return template;
}
@JsonProperty
public void setTemplate(String template) {
this.template = template;
}
@JsonProperty
public String getDefaultName() {
return defaultName;
}
@JsonProperty
public void setDefaultName(String name) {
this.defaultName = name;
}
}
Step 4. Application Class
Here.
package com.example.helloworld;
import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import com.example.helloworld.resources.HelloWorldResource;
import com.example.helloworld.health.TemplateHealthCheck;
public class HelloWorldApplication extends Application<HelloWorldConfiguration> {
public static void main(String[] args) throws Exception {
new HelloWorldApplication().run(args);
}
@Override
public String getName() {
return "hello-world";
}
@Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
// nothing to do yet
}
@Override
public void run(HelloWorldConfiguration configuration,
Environment environment) {
// nothing to do yet
}
}
Step 5. Representation Class
https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations
package com.example.helloworld.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.Length;
public class Saying {
private long id;
@Length(max = 3)
private String content;
public Saying() {
// Jackson deserialization
}
public Saying(long id, String content) {
this.id = id;
this.content = content;
}
@JsonProperty
public long getId() {
return id;
}
@JsonProperty
public String getContent() {
return content;
}
}
Step 6. Resource Class
These are essencial for Jersey. Each resource class is associated with a URI template. These are endpoints. Resource classes are used by multiple threads concurrently. In general, we recommend that resources be stateless/immutable, but it’s important to keep the context in mind. Dropwizard automatically records the duration and rate of its invocations as a Metrics Timer (@Timed). Dropwizard has one such provider built in which allows for producing and consuming Java objects as JSON objects. The provider writes out the JSON and the client receives a 200 OK
response with a content type ofapplication/json
.package com.example.helloworld.resources;
import com.example.helloworld.api.Saying;
import com.codahale.metrics.annotation.Timed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.concurrent.atomic.AtomicLong;
import java.util.Optional;
@Path("/hello-world")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {
private final String template;
private final String defaultName;
private final AtomicLong counter;
public HelloWorldResource(String template, String defaultName) {
this.template = template;
this.defaultName = defaultName;
this.counter = new AtomicLong();
}
@GET
@Timed
public Saying sayHello(@QueryParam("name") Optional<String> name) {
final String value = String.format(template, name.orElse(defaultName));
return new Saying(counter.incrementAndGet(), value);
}
}
http://www.dropwizard.io/1.2.0/docs/manual/core.html#man-core-resources-parameters
Step 7. Register a Resource
Into Application class registers the Resource classes using Configuration parameters. Environment: it is the registry
@Override
public void run(HelloWorldConfiguration configuration,
Environment environment) {
final HelloWorldResource resource = new HelloWorldResource(
configuration.getTemplate(),
configuration.getDefaultName()
);
environment.jersey().register(resource);
}
Step 8. Health checks
We strongly recommend that all of your applications have at least a minimal set of health checks. This is part of Metrics projects.
package com.example.helloworld.health;
import com.codahale.metrics.health.HealthCheck;
public class TemplateHealthCheck extends HealthCheck {
private final String template;
public TemplateHealthCheck(String template) {
this.template = template;
}
@Override
protected Result check() throws Exception {
final String saying = String.format(template, "TEST");
if (!saying.contains("TEST")) {
return Result.unhealthy("template doesn't include a name");
}
return Result.healthy();
}
}
Add it to the Environment:
@Override
public void run(HelloWorldConfiguration configuration,
Environment environment) {
final HelloWorldResource resource = new HelloWorldResource(
configuration.getTemplate(),
configuration.getDefaultName()
);
final TemplateHealthCheck healthCheck =
new TemplateHealthCheck(configuration.getTemplate());
environment.healthChecks().register("template", healthCheck);
environment.jersey().register(resource);
}
Step 9. Build FAT Jars
We recommend that you build your Dropwizard applications as “fat” JAR files. This allows you to build a single deployable artifact which you can promote from your staging environment to your QA environment to your production environment without worrying about differences in installed libraries.
Configure Maven to include a step more in package step: maven-shade-plugin
Since Dropwizard is using the Java ServiceLoader functionality to register and load extensions, the minimizeJar option of the maven-shade-plugin will lead to non-working application JARs.
http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html
https://maven.apache.org/plugins/maven-shade-plugin/shade-mojo.html#minimizeJar
Step 10. Versioning the Jars
This can be handy when trying to figure out what version of your application you have deployed on a machine.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
Step 11. Build and Run the package
Run: mvn clean package
Run: java -jar target/api-base-1.0-SNAPSHOT.jar server hello-world.yml
Where server
indicates which runs your application as an HTTP server:
Open: http://localhost:8080/hello-world
Step 12. Admin Console
One of the main reasons for using Dropwizard is the out-of-the-box operational tools it provides
Open: http://localhost:8081/
When a Jetty worker thread is handling an incoming HTTP request, the thread name is set to the method and URI of the request. This can be _very _helpful when debugging a poorly-behaving request.
References
http://www.dropwizard.io/1.2.0/docs/getting-started.html#creating-an-application-class
http://www.dropwizard.io/1.2.0/docs/
https://books.sonatype.com/mvnref-book/reference/
http://wiki.fasterxml.com/JacksonHome
http://metrics.dropwizard.io/3.2.3/
https://github.com/google/guava
http://www.hibernate.org/subprojects/validator.html
http://hc.apache.org/httpcomponents-client-ga/index.html
http://freemarker.sourceforge.net/
http://joda-time.sourceforge.net/
https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations