博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dropwizard官方教程(一) 入门
阅读量:2251 次
发布时间:2019-05-09

本文共 15075 字,大约阅读时间需要 50 分钟。

转载:

入门

本文将指导您完成一个简单的Dropwizard的Hello World项目。在此过程中,我们将解释各种底层库及其作用,以及Dropwizard中的重要概念,并建议一些组织技术来帮助您的项目能持续健康地增长。

概览

Dropwizard跨越了作为lib库和框架之间的界限。其目标是为生产就绪的Web应用程序所需的所有内容提供高性能,高可靠的实现。并且这些功能被封装到可重用的库中,因此您的应用程序仍然很精简和专注,从而缩短了产品上线时间和维护负担。

用于HTTP的Jetty

因为您的Web应用程序不能没有HTTP,Dropwizard使用 ,一个令人难以置信的调优HTTP服务器直接嵌入到您的项目中。Dropwizard项目没有将应用程序交给复杂的应用程序服务器,而是有一个main方法运行HTTP服务器。将您的应用程序作为一个简单的过程运行,消除了生产中Java的许多令人讨厌的方面(没有PermGen问题,没有应用程序服务器配置和维护,没有神秘的部署工具,没有类加载器问题,没有隐藏的应用程序日志,没有尝试调整单个垃圾收集器与多个应用程序工作负载一起工作)并允许您使用所有现有的Unix进程管理工具。

用于REST的Jersey

为了构建RESTful Web应用程序,我们发现在功能或性能方面没有任何东西胜过(参考实现)。它允许您编写干净,可测试的类,这些类可以优雅地将HTTP请求映射到简单的Java对象。它支持流输出,矩阵URI参数,条件GET请求等等。

用于JSON的Jackson

在数据格式方面,JSON已成为网络的通用语言,而则是JVM上的JSON之王。除了快速闪电之外,它还有一个复杂的对象映射器,允许您直接导出域模型。

用于监控的Metrics

有助于分析问题,为您提供无与伦比的洞悉您的生产环境中的代码的行为。

其他集成的工具

除了,和之外,Dropwizard还包括一些库,可以帮助您更快速高效地开发。

  • 除了高度优化的不可变数据结构外,还提供了越来越多的类来加速Java的开发。
  • 和用于高性能和灵活的日志记录。
  • 是参考实现,它提供了一个简单的声明性框架,用于验证用户输入并生成有用且易于i18n的错误消息。
  • 在和客户端库允许都与其他Web服务低收入和高层次的互动。
  • 是使用Java的关系数据库最直接的方法。
  • 是在整个开发和发布周期中检查数据库模式的好方法,应用高级数据库重构而不是一次性DDL脚本。
  • 和是简单的模板系统,适用于面向用户的更多应用程序。
  • 是一个非常完整,理智的库,用于处理日期和时间。

既然你已经了解到这了,那就让我们深入挖掘吧!

使用Maven进行设置

我们建议您将用于新的Dropwizard应用程序。如果你是一个大型的 / ,, ,,或粉丝,这很酷,但我们使用Maven,我们将在使用Maven时通过这个示例应用程序。如果您对Maven如何运作有任何疑问, 应该有你想要的东西。

你有三种选择:

  1. 使用创建项目:

    mvn archetype:generate -DarchetypeGroupId=io.dropwizard.archetypes -DarchetypeArtifactId=java-simple -DarchetypeVersion=[REPLACE WITH A VALID DROPWIZARD VERSION]
  2. 看一下

  3. 请按照以下教程了解如何将其包含在现有项目中

教程

首先,dropwizard.version使用当前版本的Dropwizard(1.3.5)向POM 添加属性:

INSERT VERSION HERE

dropwizard-core库添加为依赖项:

io.dropwizard
dropwizard-core
${dropwizard.version}

很好,这些足够了。我们现在已经建立了一个Maven项目,现在是时候开始编写真正的代码了。

创建配置类

每个Dropwizard应用程序都有自己的Configuration类的子类,它指定特定的环境参数。这些参数在配置文件中指定,该文件被反序列化为应用程序配置类的实例。

我们将要构建的应用程序是一个高性能的Hello World服务。我们需要至少指定两件事:一个用于说出问候的模板和一个默认名称,以防用户未指定其名称。

这是我们的配置类的样子,完整的:

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;    }}

这里有很多知识点,所以让我们解释一下吧。

当从YAML文件反序列化该类时,它将从YAML对象中提取两个根级别字段:template,我们的Hello World说明的模板,以及defaultName要使用的默认名称。templatedefaultName都标注了@NotEmpty,所以如果YAML配置文件有任何空值或缺少template完全的信息会抛出异常,并且应用程序将无法启动。

templatedefaultName的getter和setter都有注释 @JsonProperty,这允许Jackson既可以从YAML文件反序列化属性,也可以序列化它。

注意

从YAML到您的应用程序Configuration实例的映射由完成。这意味着您的Configuration类可以使用Jackson的所有。验证@NotEmpty由Hibernate Validator处理,它具有 供您使用。

我们的YAML文件将如下所示,完整的:

template: Hello, %s!defaultName: Stranger

Dropwizard有许多比这更多的配置参数,但他们都有健全的默认值,这样可以保持你的配置文件小,重点突出。

因此,将YAML文件保存在您计划运行的jar的目录中(见下文)hello-world.yml,因为我们很快就会启动并运行,我们将需要它。接下来,我们正在创建我们的应用程序类!

创建应用程序类

结合项目的Configuration子类,Application子类构成了Dropwizard应用程序的核心。所述Application类启动各bundle和command命令,其提供基本功能在一起(稍后会详细介绍)。但是现在,我们 HelloWorldApplication看起来像这样:

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
{ public static void main(String[] args) throws Exception { new HelloWorldApplication().run(args); } @Override public String getName() { return "hello-world"; } @Override public void initialize(Bootstrap
bootstrap) { // nothing to do yet } @Override public void run(HelloWorldConfiguration configuration, Environment environment) { // nothing to do yet }}

如您所见,HelloWorldApplication使用应用程序的配置类型HelloWorldConfiguration进行参数化。initialize方法用于在运行应用程序之前配置所需应用程序的各个方面,如bundle,配置源提供程序等。此外,我们还添加了一个static main方法,它将成为我们应用程序的入口点。现在,我们没有实现任何功能,所以我们的run方法有点无聊。让我们解决这个问题!

创建表示类

在我们进入Hello World应用程序的细节之前,我们需要停下来思考一下我们的API。幸运的是,我们的应用程序需要符合行业标准,它规定了Hello World的以下JSON表示:

{  "id": 1,  "content": "Hi!"}

id字段是该问候的唯一标识符,并且content是该问候的文本表示。(值得庆幸的是,这是一个相当直接的行业标准。)

要对此表示进行建模,我们将创建一个表示类:

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;    }}

这是一个非常简单的POJO,但有一些值得注意的事情。

首先,它是不可改变的。这使得Saying实例在多线程环境以及单线程环境中非常容易推理。其次,它使用JavaBeans标准idcontent属性。这允许将其序列化为我们需要的JSON。Jackson对象映射代码将id使用返回值填充JSON对象的字段#getId(),同样使用content#getContent()。最后,bean利用验证来确保内容大小不超过3。

注意

这里的JSON序列化由Jackson完成,它支持的不仅仅是像这样的简单JavaBean对象。除了复杂的集,您甚至可以编写自定义序列化程序和反序列化程序。

既然我们已经有了表示类,接下来学习下资源。

创建资源类

Jersey资源是Dropwizard应用程序的核心。每个资源类都与URI模板相关联。对于我们的应用程序,我们需要从URI /hello-world返回一个Saying 实例,因此我们的资源类如下所示:

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
name) { final String value = String.format(template, name.orElse(defaultName)); return new Saying(counter.incrementAndGet(), value); }}

HelloWorldResource有两个注释:@Path@Produces@Path("/hello-world") 告诉Jersey,这个资源可以在URI上访问/hello-world,并且 @Produces(MediaType.APPLICATION_JSON)让Jersey的内容协商代码知道这个资源产生的表示形式是application/json

HelloWorldResource采用两个参数进行构造:template它用于产生问候语,当用户拒绝告诉我们他们的名字时使用defaultNameAtomicLong为我们提供了一种廉价,线程安全的方法来生成唯一(ish)ID。

警告

资源类由多个线程同时使用。一般来说,我们建议资源是无状态/不可变的,但重要的是要记住上下文。

#sayHello(Optional<String>)是这个类的核心,这是一个相当简单的方法。@QueryParam("name")注解告诉Jersey从请求参数字符串中把name参数赋值给方法中的name参数。如果客户端发送请求 /hello-world?name=DougiesayHello将被调用Optional.of("Dougie"); 如果name查询字符串中没有参数,sayHello则将调用Optional.absent()。(支持Guava的Optional是Dropwizard为Jersey的现有功能添加的一些额外的功能)

注意

如果客户端发送请求/hello-world?name=sayHello将被调用 Optional.of("")。这可能看起来很奇怪,但这遵循标准(应用程序可能具有不同的行为,具体取决于参数是否为空而不存在)。如果你希望/hello-world?name=返回“Hello,Stranger!”,可以用NonEmptyStringParam替换 Optional<String>参数。有关资源参数的更多信息,请参阅

sayHello方法内部,我们递增计数器,使用格式化模板String.format(String,Object...) ,并返回一个Saying新实例。

因为sayHello带有注释@Timed,Dropwizard会自动将其调用的持续时间和速率记录为Metrics Timer。

一旦sayHello返回,Jersey就会获取Saying实例并查找可以将Saying实例写为application/json的转换类。Dropwizard内置了一个这样的转换类,允许使用Java对象生成JSON对象,JSON对象生成Java对象。该转换类生成JSON,客户端会收到200 OK 的内容类型为application/json的响应。

注册资源

不过,在这一切生效之前,我们需要回到HelloWorldApplication并注册这个新的资源类。在run方法中,我们可以从HelloWorldConfiguration实例中读取模板和默认名称 ,创建一个新HelloWorldResource实例,然后将其添加到应用程序的Jersey环境中:

@Overridepublic void run(HelloWorldConfiguration configuration,                Environment environment) {    final HelloWorldResource resource = new HelloWorldResource(        configuration.getTemplate(),        configuration.getDefaultName()    );    environment.jersey().register(resource);}

当我们的应用程序启动时,我们使用配置文件中的参数创建一个新的资源类实例,并将其交给它Environment,它就像应用程序可以执行的所有操作的注册表。

注意

Dropwizard应用程序可以包含许多资源类,每个资源类都对应于自己的URI。只需添加另一个@Path注释资源类,并使用新类的实例调用register方法即可。

在我们走得太远之前,我们应该为我们的应用添加健康检查。

创建健康检查

运行状况检查为您提供了一种向应用程序添加小测试的方法,以便您验证应用程序在生产中是否正常运行。我们强烈建议您的所有应用程序至少具有一组最小的运行状况检查。

注意

事实上,我们强烈推荐这一点,如果你忽略了为你的项目添加健康检查,Dropwizard会唠叨你。

由于格式化字符串在应用程序运行时不太可能失败(与数据库连接池不同),因此我们必须在这里想一些创意。我们将添加一个运行状况检查,以确保我们可以格式化提供的模板:

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();    }}

TemplateHealthCheck 检查两件事:提供的模板确实是格式良好的格式字符串,模板确实能生成具有给定名称的输出。

如果字符串不是格式良好的格式字符串(例如,有人意外地将Hello,%s%放入 配置文件中),那么String.format(String, Object...)将抛出一个IllegalFormatException ,并且运行状况检查将隐式失败。如果呈现的问候语不包括测试字符串,则运行状况检查将通过返回不健康的Result而显式失败。

添加健康检查

与Dropwizard中的大多数内容一样,我们使用适当的参数创建一个新实例并将其添加到Environment

@Overridepublic 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);}

现在我们快要准备好了!

建立工程的JAR包

我们建议把Dropwizard应用程序构建为“单” JAR文件-一个.jar包含所有的运行应用程序所需的.class文件。这允许您构建单个可部署工件,您可以将其从开发环境升级到测试环境再到生产环境,而无需担心已安装库中的差异。要开始构建我们的Hello World应用程序作为单JAR,我们需要配置一个名为maven-shade的Maven插件。在文件的<build><plugins>部分中pom.xml,添加以下内容:

org.apache.maven.plugins
maven-shade-plugin
2.3
true
*:*
META-INF/*.SF
META-INF/*.DSA
META-INF/*.RSA
package
shade
com.example.helloworld.HelloWorldApplication

这将配置Maven在其package阶段执行以下操作:

  • 生成一个pom.xml文件,该文件不包含在单JAR中的库的依赖项的内容。
  • 从已签名的JAR中排除所有数字签名。如果不这样做,则Java认为签名无效,并且不会加载或运行您的JAR文件。
  • 整理JAR中META-INF/services的各种条目而不是覆盖它们。(如果没有那些,那么Dropwizard和Jersey都不会工作)
  • com.example.helloworld.HelloWorldApplication设为JAR MainClass。这将允许您使用java -jar运行JAR 。

警告

如果您的应用程序具有必须签名的依赖项(例如,提供程序或其他可信库),则必须在 该库的maven-shade-plugin配置中添加,并将该JAR包含在类路径中。

警告

由于Dropwizard使用Java 功能来注册和加载扩展,因此maven-shade-plugin的选项将导致应用程序JAR不能正常工作。

版本化您的JAR

Dropwizard也可以使用项目版本,如果它嵌入在JAR的清单中作为 Implementation-Version。要使用Maven嵌入此信息,请将以下内容添加到文件的 <build><plugins>部分pom.xml

org.apache.maven.plugins
maven-jar-plugin
2.4
true

在尝试确定您在计算机上部署的应用程序版本时,这非常方便。

完成配置后,进入项目目录并运行mvn package(或从IDE 运行package 目标)。你应该看到这样的东西:

[INFO] Including org.eclipse.jetty:jetty-util:jar:7.6.0.RC0 in the shaded jar.[INFO] Including com.google.guava:guava:jar:10.0.1 in the shaded jar.[INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar.[INFO] Including org.hibernate:hibernate-validator:jar:4.2.0.Final in the shaded jar.[INFO] Including javax.validation:validation-api:jar:1.0.0.GA in the shaded jar.[INFO] Including org.yaml:snakeyaml:jar:1.9 in the shaded jar.[INFO] Replacing original artifact with shaded artifact.[INFO] Replacing /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT.jar with /Users/yourname/Projects/hello-world/target/hello-world-0.0.1-SNAPSHOT-shaded.jar[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 8.415s[INFO] Finished at: Fri Dec 02 16:26:42 PST 2011[INFO] Final Memory: 11M/81M[INFO] ------------------------------------------------------------------------

恭喜!你已经建立了你的第一个Dropwizard项目!现在是时候运行了!

运行您的应用程序

现在您已经构建了一个JAR文件,现在是时候运行它了。

在项目目录中,运行以下命令:

java -jar target/hello-world-0.0.1-SNAPSHOT.jar

您应该看到如下内容:

usage: java -jar hello-world-0.0.1-SNAPSHOT.jar       [-h] [-v] {server} ...positional arguments:  {server}               available commandsoptional arguments:  -h, --help             show this help message and exit  -v, --version          show the service version and exit

Dropwizard接受第一个命令行参数并将其分派给匹配的命令。在这种情况下,唯一可用的命令是server,将您的应用程序作为HTTP服务器运行。该 server命令需要一个配置文件,所以让我们继续为它提供 :

java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml

您应该看到如下内容:

INFO  [2011-12-03 00:38:32,927] io.dropwizard.cli.ServerCommand: Starting hello-worldINFO  [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOTINFO  [2011-12-03 00:38:32,936] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}INFO  [2011-12-03 00:38:32,999] com.sun.jersey.server.impl.application.WebApplicationImpl: Initiating Jersey application, version 'Jersey: 1.10 11/02/2011 03:53 PM'INFO  [2011-12-03 00:38:33,041] io.dropwizard.setup.Environment:    GET     /hello-world (com.example.helloworld.resources.HelloWorldResource)INFO  [2011-12-03 00:38:33,215] org.eclipse.jetty.server.handler.ContextHandler: started o.e.j.s.ServletContextHandler{/,null}INFO  [2011-12-03 00:38:33,235] org.eclipse.jetty.server.AbstractConnector: Started BlockingChannelConnector@0.0.0.0:8080 STARTINGINFO  [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING

您的Dropwizard应用程序现在正在侦听8080应用程序请求和8081 管理请求的端口。如果按^C,应用程序将正常关闭,首先关闭服务器套接字,然后等待处理正在进行的请求,然后关闭进程本身。

大功告成,试一下!

我们正在产生问候语,真棒。当然你的应用程序能做到的远远不止这些。使用Dropwizard的主要原因之一是它提供的开箱即用的操作工具,所有这些工具都可以 找到。

如果访问 ,则可以看到所有应用程序的指标都表示为JSON对象。

访问 可以让您快速获得在这个过程中运行的所有线程的线程转储。

提示

当Jetty工作线程处理传入的HTTP请求时,线程名称将设置为请求的方法和URI。在调试性能不佳的请求时,这非常有用。

在运行 。你应该看到这样的东西:

* deadlocks: OK* template: OK

template这是你的TemplateHealthCheck的结果,毫不奇怪地通过了。 deadlocks是一个内置的运行状况检查,它查找死锁的JVM线程并打印出列表(如果找到)。

下一步

嗯,恭喜。您已经准备好用于生产的Hello World应用程序(除了缺少测试),它能够每秒执行30,000-50,000个请求。希望您已经了解了Dropwizard如何将Jetty,Jersey,Jackson和其他稳定,成熟的库结合起来,为开发RESTful Web应用程序提供了一个非凡的平台。

Dropwizard还有很多内容(命令commands,绑定bundles,servlet,高级配置,验证validation,HTTP客户端,数据库客户端,视图等),所有这些都在中介绍。

官网

作者:程序员文集
链接:https://www.jianshu.com/p/3bb308c9bbcb
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的文章
冒泡排序和快速排序
查看>>
直方图均衡化
查看>>
校招面试知识点复习之计算机网络
查看>>
C++类实例化时的内存分配
查看>>
C++重载赋值运算符
查看>>
Android内存监控与分析(四):内存分析实例演示
查看>>
nodejs内存溢出 FATAL ERROR: CALL_AND_RETRY_0 Allocation failed – process out of memory(转载)
查看>>
测试者出的APP测试面试题
查看>>
移动测试工程师必须知道的10个开源框架
查看>>
解决:忘记Jenkins管理员密码
查看>>
python 自动生成文档
查看>>
Python 服务器监控
查看>>
shell 搜索目录下所有文件包含某个内容的文件
查看>>
Linux 系统中用户切换(su user与 su - user 的区别)
查看>>
hiredis问题:libhiredis.so.0.13: cannot open shared object file
查看>>
SonarQube 因为中文文件名报错
查看>>
Docker CI: Jenkins 配置凭据和Job
查看>>
Jenkins Pipeline 介绍和实战
查看>>
Lua – Table(数组遍历)
查看>>
Docker CI: Jenkins 主从模式的权限问题
查看>>