原文鏈接:http://www.dropwizard.io/1.2.0/docs/getting-started.html
Getting Start
Getting Startedwill guide you through the process of creating a simple Dropwizard Project: Hello World. Along the way, we’ll explain the various underlying libraries and their roles, important concepts in Dropwizard, and suggest some organizational techniques to help you as your project grows. (Or you can just skip to the?fun part.)
入門指南將會(huì)引導(dǎo)你完成創(chuàng)建一個(gè)簡單的Dropwizard項(xiàng)目:Hello Word蹋绽。整個(gè)過程中俯萌,我們會(huì)介紹其引用的底層類庫和作用羔味,Zropwizard框架的重要概念抖棘,在項(xiàng)目實(shí)現(xiàn)過程中介紹一些組織性的技術(shù)毫炉。(你也可以跳過Getting Start步驟)
Overview
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.
Dropwizard跨越了類庫和框架之間的界限萍肆。其目的是為Web應(yīng)用程序提供一種可靠的實(shí)現(xiàn)方案缠导。由于此功能被提取到可重用的類庫中廉羔,因此你的應(yīng)用程序仍然精簡和集中,從而縮短上市時(shí)間和維護(hù)負(fù)擔(dān)僻造。
Jetty for HTTP
Because you can’t be a web application without HTTP, Dropwizard uses the Jetty HTTP library to embed an incredibly tuned HTTP server directly into your project. Instead of handing your application off to a complicated application server, Dropwizard projects have a main method which spins up an HTTP server. Running your application as a simple process eliminates a number of unsavory aspects of Java in production (no PermGen issues, no application server configuration and maintenance, no arcane deployment tools, no class loader troubles, no hidden application logs, no trying to tune a single garbage collector to work with multiple application workloads) and allows you to use all of the existing Unix process management tools instead.
Web應(yīng)用程序離不開HTTP憋他,Zropwizard框架直接將Jetty Http插件(Http服務(wù)器)嵌入到你的Web應(yīng)用程序中。你不需要將項(xiàng)目交給一個(gè)復(fù)雜的Web服務(wù)器髓削,Zropwizard項(xiàng)目提供一個(gè)main方法快速啟動(dòng)一個(gè)HTTP服務(wù)器(Jetty)竹挡。通過一個(gè)簡單的過程運(yùn)行你的Java應(yīng)用程序而排除一系列復(fù)雜的事情。(沒有PermGen問題立膛,沒有應(yīng)用服務(wù)器配置和維護(hù)揪罕,沒有復(fù)雜的部署工具,沒有類加載器的困擾宝泵,沒有隱藏的應(yīng)用日志好啰,不用調(diào)試?yán)厥掌鱽斫鉀Q多應(yīng)用負(fù)載),允許使用所有現(xiàn)成的Unix進(jìn)程管理工具鲁猩。
Jersey for REST
For building RESTful web applications, we’ve found nothing beats?Jersey(the?JAX-RS?reference implementation) in terms of features or performance. It allows you to write clean, testable classes which gracefully map HTTP requests to simple Java objects. It supports streaming output, matrix URI parameters, conditional GET requests, and much, much more.
構(gòu)建RESTful風(fēng)格的Web應(yīng)用程序坎怪,我們沒有發(fā)現(xiàn)任何能夠打敗Jersey的框架。它允許您編寫簡潔廓握,可測試的類搅窿,將HTTP請求正確地映射到簡單的Java對(duì)象。它支持流輸出隙券,解析URI參數(shù)男应,條件GET請求等等。
Jackson for JSON
In terms of data formats, JSON has become the web’s?lingua franca, and?Jackson?is the king of JSON on the JVM. In addition to being lightning fast, it has a sophisticated object mapper, allowing you to export your domain models directly.
目前的數(shù)據(jù)格式娱仔,JSON已經(jīng)是一種通用的數(shù)據(jù)結(jié)構(gòu)沐飘,Jackson是JVM解析JSON數(shù)據(jù)的霸主。除了速度快,Jackson還有一套對(duì)象映射器耐朴,允許你直接導(dǎo)出你的數(shù)據(jù)模型借卧。
Metrics for metrics
The?Metrics?library rounds things out, providing you with unparalleled insight into your code’s behavior in your production environment.
Metrics插件讓你代碼執(zhí)行透明化,對(duì)你生產(chǎn)環(huán)境的代碼提供無與倫比的觀察能力筛峭。
And Friends
In addition to?Jetty,Jersey, andJackson, Dropwizard also includes a number of libraries to help you ship more quickly and with fewer regrets.
除了Jetty铐刘、Jersey、Jackson之外影晓,Dropwizard還包括許多其他類庫幫助你的應(yīng)用開發(fā)镰吵,減少煩惱。
Guava, which, in addition to highly optimized immutable data structures, provides a growing number of classes to speed up development in Java.
除了高度優(yōu)化的不可變數(shù)據(jù)結(jié)構(gòu)之外挂签,Guava還提供了越來越多的類庫來加速Java開發(fā)疤祭。
Logback?and?slf4j?for performant and flexible logging.
Logback和slf4j用于執(zhí)行和靈活的日志記錄。
Hibernate Validator, the?JSR 349?reference implementation, provides an easy, declarative framework for validating user input and generating helpful and i18n-friendly error messages.
Hibernate Validator饵婆,JSR 349參考實(shí)現(xiàn)勺馆,為驗(yàn)證用戶輸入提供了一個(gè)簡單的聲明框架,并生成有用的和易于使用的I18n友好的錯(cuò)誤消息啦辐。
The?Apache HttpClient?and?Jersey?client libraries allow for both low- and high-level interaction with other web services.
Apache HttpClient和Jersey客戶端庫允許與其他Web服務(wù)進(jìn)行低級(jí)和高級(jí)別的交互谓传。
JDBI?is the most straightforward way to use a relational database with Java.
JDBI是使用Java的關(guān)系數(shù)據(jù)庫最直接的方法。
Liquibase?is a great way to keep your database schema in check throughout your development and release cycles, applying high-level database refactorings instead of one-off DDL scripts.
在開發(fā)和發(fā)布周期中芹关,Liquibase是保持?jǐn)?shù)據(jù)庫模式的重要方法续挟,應(yīng)用高級(jí)數(shù)據(jù)庫重構(gòu)而不是一次性DDL腳本。
Freemarker?and?Mustache?are simple templating systems for more user-facing applications.
Freemarker和Mustache是??簡單的系統(tǒng)模板侥衬,適用于面向更多用戶的應(yīng)用程序诗祸。
Joda Time?is a very complete, sane library for handling dates and times.
Joda? Time是一個(gè)非常完整明智的類庫 ,用于處理日期和時(shí)間轴总。
Now that you’ve gotten the lay of the land, let’s dig in!
現(xiàn)在你已經(jīng)得到了這片土地直颅,讓我們開始吧!
Setting Up Using Maven
We recommend you use?Maven?for new Dropwizard applications. If you’re a big?Ant/Ivy,Buildr,Gradle,SBT,Leiningen, or?Gant?fan, that’s cool, but we use Maven, and we’ll be using Maven as we go through this example application. If you have any questions about how Maven works,Maven: The Complete Reference?should have what you’re looking for.
我們推薦你使用Maven創(chuàng)建一個(gè)新的Dropwizard應(yīng)用怀樟。如果你是一個(gè)Ant/lvy功偿、Buildr、Gradle往堡、SBT械荷、Leiningen或者Grnt的忠實(shí)粉絲,這是非陈腔遥酷的事情吨瞎,但是我們事例這里使用Maven。如果你有任何關(guān)于Maven的疑問穆咐,你可以查詢Maven官方文檔颤诀。
You have three alternatives from here:
你有以下三個(gè)選擇:
1字旭、Create a project using?dropwizard-archetype
使用dropwizard-archetype(原型)創(chuàng)建項(xiàng)目
mvn archetype:generate -DarchetypeGroupId=io.dropwizard.archetypes -DarchetypeArtifactId=java-simple -DarchetypeVersion=[REPALCE WITH A VALID DROPWIZARD VERSION]
2、Look at the?dropwizard-example
3崖叫、Follow the tutorial below to see how you can include it in your existing project
在你的項(xiàng)目中遵循以下原則
Tutorial
First, add adropwizard.versionproperty to your POM with the current version of Dropwizard (which is 1.2.0):
首先遗淳,為你的項(xiàng)目POM中添加一個(gè)dropwizard.version屬性,使用當(dāng)前版本的Dropwizard(即1.2.0)
<properties>
? ? ? ? ? ? <dropwizard.version>INSERT VERSION HERE</dropwizard.version>
</properties>
Add the dropwizard-core library as a dependency:
添加dropwizard-core類庫:
<dependencies>
? ? ? ? ? ?<dependency>
? ? ? ? ? ? ? ? ? ? ? <groupId>io.dropwizard</groupId>
? ? ? ? ? ? ? ? ? ? ? <artifactId>dropwizard-core</artifactId>
? ? ? ? ? ? ? ? ? ? ? <version>${dropwizard.version}</version>
? ? ? ? ? ?</dependency>
</dependencies>
Alright, that’s enough XML. We’ve got a Maven project set up now, and it’s time to start writing real code.
好了心傀,足夠的XML洲脂。我們已經(jīng)擁有了一個(gè)Maven項(xiàng)目,可以開始寫代碼了剧包。
Creating A Configuration Class
Each Dropwizard application has its own subclass of the Configuration class which specifies environment-specific parameters. These parameters are specified in a?YAML?configuration file which is deserialized to an instance of your application’s configuration class and validated.
每個(gè)Dropwizard應(yīng)用都有自己指定環(huán)境參數(shù)的配置類。在一個(gè)YAML配置文件中指定參數(shù)往果,yaml文件會(huì)被反序列化為應(yīng)用配置類的實(shí)例并進(jìn)行驗(yàn)證疆液。
The application we’ll be building is a high-performance Hello World service, and one of our requirements is that we need to be able to vary how it says hello from environment to environment. We’ll need to specify at least two things to begin with: a template for saying hello and a default name to use in case the user doesn’t specify their name.
我們將要構(gòu)建的應(yīng)用是一個(gè)高性能的Hello World服務(wù),要求我們需要改變從環(huán)境到環(huán)境的去調(diào)用hello服務(wù)陕贮。我們至少要說明兩件事情:一個(gè)是hello服務(wù)的模版和一個(gè)特定的服務(wù)名稱堕油。
Here’s what our configuration class will look like, full?example conf here:
以下是我們配置類的例子:
packagecom.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() { returndefaultName;
}
@JsonProperty
public void setDefaultName(Stringname) {
this.defaultName=name;
}
}
There’s a lot going on here, so let’s unpack a bit of it.
接下來有很多事情要做,讓我們開始去嘗試它肮之。
When this class is deserialized from the YAML file, it will pull two root-level fields from the YAML object:template, the template for our Hello World saying, and defaultName, the default name to use. Both template and defaultName are annotated with @NotEmpty, so if the YAML configuration file has blank values for either or is missing template entirely an informative exception will be thrown, and your application won’t start.
這個(gè)配置類從YAML配置文件反序列化掉缺,將從YAML文件中匹配根節(jié)點(diǎn)字段:template,Hello World服務(wù)模板以及默認(rèn)名稱戈擒。template和defaultName都使用了@NotEmpty注解眶明,所以如果你的YAML配置文件中沒有對(duì)應(yīng)的值或者沒有模板信息,你的應(yīng)用將會(huì)出錯(cuò)并且不能運(yùn)行筐高。
Both the getters and setters for template and defaultName are annotated with @JsonProperty, which allows Jackson to both deserialize the properties from a YAML file but also to serialize it.
template和defaultName屬性的setter和getter方法都使用了@JsonProperty注解搜囱,允許Jackson反序列化屬性值從YAML配置文件中,也可以序列化柑土。
Note
The mapping from YAML to your application’s Configuration instance is done by?Jackson. This means your Configuration class can use all of Jackson’s?object-mapping annotations. The validation of @NotEmpty is handled by Hibernate Validator, which has a?wide range of built-in constraints?for you to use.
注:
YAML配置文件信息通過Jackson映射到應(yīng)用配置實(shí)例上蜀肘,這意味著你的配置類可以使用所有的Jackson的映射注解。@NotEmpty注解的由Hibernate Validator驗(yàn)證稽屏,具有廣泛的內(nèi)置約束扮宠。
Our YAML file will then look like the below, full?example yml here:
我們示例的YAML文件如下,完整的yaml文件:
template:Hello, %s!
defaultName:Stranger
Dropwizard has?many?more configuration parameters than that, but they all have sane defaults so you can keep your configuration files small and focused.
Dropwizard有更多的配置參數(shù)狐榔,但是都有合適的默認(rèn)值坛增,因此你的配置文件可以保持小而簡潔。
So save that YAML file in the directory you plan to run the fat jar from (see below) as hello-world.yml, because we’ll be getting up and running pretty soon, and we’ll need it. Next up, we’re creating our application class!
因此可以把你的YAML配置文件hello-world.yml保存在你運(yùn)行目錄下(參考下文)荒叼,我們運(yùn)行項(xiàng)目需要使用配置文件轿偎。接下來,我們開始創(chuàng)建一個(gè)應(yīng)用主要類文件被廓。
Creating An Application Class
Combined with your project’s Configuration subclass, its Application subclass forms the core of your Dropwizard application. The Application class pulls together the various bundles and commands which provide basic functionality. (More on that later.) For now, though, our HelloWorld Application looks like this:
結(jié)合項(xiàng)目配置類坏晦,這個(gè)應(yīng)用程序主類是Dropwizard應(yīng)用程序的核心,Application主類將各種綁定和命令結(jié)合在一起提供基本的功能。(稍后)現(xiàn)在昆婿,我們HelloWorld服務(wù)的Application類文件是像這樣的:
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
}
}
As you can see,HelloWorld Application is parameterized with the application’s configuration type,HelloWorld Configuration. An initialize method is used to configure aspects of the application required before the application is run, like bundles, configuration source providers, etc. Also, we’ve added a static main method, which will be our application’s entry point. Right now, we don’t have any functionality implemented, so our run method is a little boring. Let’s fix that!
正如你多看到的球碉,HelloWorld服務(wù)配置參數(shù)使用Application配置類來完成參數(shù)參數(shù)化。在應(yīng)用啟動(dòng)之前完成應(yīng)用所需的參數(shù)初始化工作仓蛆,比如綁定睁冬,配置源等。此外看疙,我們提供一個(gè)靜態(tài)main方法豆拨,將是我們應(yīng)用的入口。現(xiàn)在我們沒有任何功能實(shí)現(xiàn)能庆,我們的應(yīng)用顯得有點(diǎn)無聊施禾。讓我們?nèi)ネ晟莆覀兊膽?yīng)用!
Creating A Representation Class
Before we can get into the nuts-and-bolts of our Hello World application, we need to stop and think about our API. Luckily, our application needs to conform to an industry standard,RFC 1149, which specifies the following JSON representation of a Hello World saying:
在我們深入了解Hello World服務(wù)之前搁胆,我們需要停下來去思考我們的API弥搞。幸運(yùn)的是,我們的應(yīng)用需要遵從行業(yè)規(guī)范RFC 1149渠旁,規(guī)范規(guī)定了Hello World服務(wù)的JSON數(shù)據(jù)形式:
{
"id":1,
"content":"Hi!"
}
The id field is a unique identifier for the saying, and contentis the textual representation of the saying. (Thankfully, this is a fairly straight-forward industry standard.)
id字段是術(shù)語獨(dú)一無二的標(biāo)識(shí)符攀例,content是術(shù)語的表示形式。(這是一個(gè)行業(yè)標(biāo)準(zhǔn)規(guī)范)
To model this representation, we’ll create a representation class:
為了構(gòu)建這樣的數(shù)據(jù)形式顾腊,我們將創(chuàng)建一個(gè)數(shù)據(jù)模類:
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() {
returnid;
}
@JsonProperty
public String getContent() {
return content;
}
}
This is a pretty simple POJO, but there are a few things worth noting here.
這是一個(gè)非常簡單的POJO類粤铭,但是也有很多值得注意的地方。
First, it’s immutable. This makes Saying instances?very?easy to reason about in multi-threaded environments as well as single-threaded environments. Second, it uses the JavaBeans standard for the id and content properties. This allows?Jackson?to serialize it to the JSON we need. The Jackson object mapping code will populate the id field of the JSON object with the return value of #getId(), like wise with content and #getContent(). Lastly, the bean leverages validation to ensure the content size is no greater than 3.
首先投慈,Saying實(shí)例是不可變的承耿。這使得Saying實(shí)例在多線程和單線程環(huán)境都容易理解。其次伪煤,使用了JavaBeans標(biāo)準(zhǔn)的屬性id和content加袋,允許Jackson序列化實(shí)例成我們需要的JSON數(shù)據(jù)。Jackson映射對(duì)象將通過getID()方法返回值填充id字段抱既,同樣的方式使用getContent()方法返回值填充content字段职烧。最后bean通過驗(yàn)證保證content內(nèi)容長度不大于3。
Note
The JSON serialization here is done by Jackson, which supports far more than simple JavaBean objects like this one. In addition to the sophisticated set of?annotations, you can even write your custom serializers and deserializers.
注:
JSON序列化通過Jackson實(shí)現(xiàn)防泵,能夠支持更多這樣的簡單JavaBean對(duì)象蚀之。除了這些注解外,你還能自定義序列化和反序列化器捷泞。
Now that we’ve got our representation class, it makes sense to start in on the resource it represents.
現(xiàn)在我們有實(shí)體類了足删,它所代表的資源數(shù)據(jù)是有意義的。
Creating A Resource Class
Jersey resources are the meat-and-potatoes of a Dropwizard application. Each resource class is associated with a URI template. For our application, we need a resource which returns new Saying instances from the URI/hello-world, so our resource class looks like this:
Jersey資源是Dropwizard應(yīng)用程序的主要核心锁右。每個(gè)資源類都與一個(gè)URI模版關(guān)聯(lián)失受。對(duì)我們應(yīng)用讶泰,我們需要一個(gè)資源類去返回一個(gè)Saying對(duì)象從URI/hello-world,因此我們的資源類如下:
package com.example.helloworld.resources;
import com.example.helloworld.api.Saying;
import com.codahale.metrics.annotation.Timed;
import javax.ws.rs.GET;importjavax.ws.rs.Path;
import javax.ws.rs.Produces;importjavax.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 = newAtomicLong();
}
@GET
@Timed
public Saying sayHello(@QueryParam("name") Optional<name>) {
final Stringvalue = String.format(template,name.orElse(defaultName));
return new Saying(counter.incrementAndGet(),value);
}
}
Finally, we’re in the thick of it! Let’s start from the top and work our way down.
最后拂到,我們開始從淺到深地了解他痪署。
HelloWorldResource has two annotations:@Pathand@Produces.@Path("/hello-world") tells Jersey that this resource is accessible at the URI/hello-world, and @Produces(MediaType.APPLICATION_JSON) lets Jersey’s content negotiation code know that this resource produces representations which areapplication/json.
HelloWorldResource有兩個(gè)注解:@Path和@Produces。@Path("/hello-world")告訴Jersey這個(gè)resource能夠通過URI/hello-world路徑訪問到兄旬,@Produces(MediaType.APPLICATION_JSON)讓Jersey’s知道這個(gè)資源處理數(shù)據(jù)表示方式是json格式狼犯。
HelloWorldResource takes two parameters for construction: the template it uses to produce the saying and the defaultName used when the user declines to tell us their name. An AtomicLong provides us with a cheap, thread-safe way of generating unique(ish) IDs.
HelloWorldResource兩個(gè)參數(shù)的構(gòu)造器:template參數(shù)用來處理saying的內(nèi)容,defaultName用來返回默認(rèn)值當(dāng)用戶拒絕告訴我們name參數(shù)的時(shí)候领铐。AtomicLong提供一個(gè)簡潔線程安全全局唯一的ID生產(chǎn)器悯森。
Warning
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.
警告:
Resource類是多線程并發(fā)使用。一般情況下,我們推薦resources為不可變模式,這是非常重要的斯议。
#sayHello(Optional<name>) is the meat of this class, and it’s a fairly simple method. The @QueryParam("name") annotation tells Jersey to map the name parameter from the query string to the name parameter in the method. If the client sends a request to /hello-world?name=Dougie,sayHello will be called with Optional.of("Dougie"); if there is no name parameter in the query string,sayHello will be called with Optional.absent(). (Support for Guava’s Optional is a little extra sauce that Dropwizard adds to Jersey’s existing functionality.)
#sayHello(Optional)是這個(gè)resource類的主要核心巩掺,是一個(gè)簡單的方法。@QueryParam("name")注解告訴Jersey映射name參數(shù)從這個(gè)方法的查詢字符串中的name參數(shù)续膳。 如果用戶發(fā)送請求/hello-world?name=Dougie改艇,sayHello將會(huì)被調(diào)用Optional.of("Dougie");如果請求中沒有name參數(shù)坟岔,sayHello將會(huì)被調(diào)用Optional.absent()谒兄。(支持Guava’s Optional類庫增強(qiáng)了Jersey已有的功能)
Note
If the client sends a request to /hello-world?name=,sayHello will be called with Optional.of(""). This may seem odd at first, but this follows the standards (an application may have different behavior depending on if a parameter is empty vs nonexistent). You can swap Optional parameter with NonEmpty String Param if you want /hello-world?name= to return “Hello, Stranger!” For more information on resource parameters see?the documentation
注:
如果客戶端發(fā)送請求/hello-world?name=,sayHello將被調(diào)用Optional.of("")社付。這看起來奇怪承疲,但是符合標(biāo)準(zhǔn)(服務(wù)可能有不同的行為依據(jù)傳入?yún)?shù)是否為空不存在)。如果你想/hello-world?name=返回“Hello, Stranger!”你可以使用非空字符參數(shù)替換?Optional<String>鸥咖,更多的資源參數(shù)信息參考官方文檔燕鸽。
In side the sayHello method, we increment the counter, format the template using String.format(String,Object...), and return a new Saying instance.
在sayHello方法中,我們增加了計(jì)數(shù)器啼辣,使用String.format(String,Object...)格式化template啊研,返回一個(gè)Saying實(shí)例。
Because sayHello is annotated with@Timed, Dropwizard automatically records the duration and rate of its invocations as a Metrics Timer.
因?yàn)閟ayHello帶有@Timed注解鸥拧,Dropwizard自動(dòng)記錄方法服務(wù)持續(xù)的時(shí)間和方法服務(wù)速率党远。
Once sayHello has returned, Jersey takes the Saying instance and looks for a provider class which can write Saying instances as application/json. 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 200OK response with a content type of application/json.
一旦sayHello有返回結(jié)果,Jersey就會(huì)采用Saying實(shí)例并尋找一個(gè)可以將Saying實(shí)例寫為application / json的提供者類富弦。Dropwizard內(nèi)置了一個(gè)這樣的提供者沟娱,它允許生成和使用Java對(duì)象作為JSON對(duì)象。提供者寫出JSON對(duì)象腕柜,客戶端接收到200的結(jié)果和application/json類型的數(shù)據(jù)內(nèi)容济似。
Registering A Resource
Before that will actually work, though, we need to go back to HelloWorldApplication and add this new resource class. In its run method we can read the template and default name from the HelloWorldConfiguration instance, create a new HelloWorldResource instance, and then add it to the application’s Jersey environment:
在啟動(dòng)項(xiàng)目提供服務(wù)之前矫废,我們需要回到HelloWorldApplication類中添加一個(gè)資源類。在run方法中我們讀取template和default name屬性從HelloWorldConfiguration實(shí)例碱屁,創(chuàng)建一個(gè)新的?HelloWorldResource實(shí)例并將其注冊到Jersey環(huán)境中:
@Override
public void run(HelloWorldConfiguration configuration, Environment environment) { final HelloWorldResource resource = new HelloWorldResource( ? ? ?configuration.getTemplate(),
configuration.getDefaultName()
);
environment.jersey().register(resource);
}
When our application starts, we create a new instance of our resource class with the parameters from the configuration file and hand it off to the Environment, which acts like a registry of all the things your application can do.
當(dāng)應(yīng)用運(yùn)行后磷脯,我們?yōu)閞esource類創(chuàng)建一個(gè)新的實(shí)例并注入configuration 文件實(shí)例的參數(shù),像是一個(gè)可做事情的列表一樣娩脾。
Note
A Dropwizard application can contain?many?resource classes, each corresponding to its own URI pattern. Just add another @Path-annotated resource class and call register with an instance of the new class.
注:
Dropwizard應(yīng)用包含很多的resource類赵誓,每個(gè)resource類都有特定的uri模版。只需添加另一個(gè)@ Path注釋的資源類柿赊,并使用新類的實(shí)例調(diào)用注冊俩功。
Before we go too far, we should add a health check for our application.
在此,我們需要為應(yīng)用添加健康檢查碰声。
Creating A Health Check
Health checks give you a way of adding small tests to your application to allow you to verify that your application is functioning correctly in production. We?strongly?recommend that all of your applications have at least a minimal set of health checks.
健康檢查提供一種向應(yīng)用添加小型測試的方法以驗(yàn)證應(yīng)用程序正常诡蜓。我們強(qiáng)烈推薦每個(gè)應(yīng)用都至少添加一個(gè)精簡的健康檢查。
Note
We recommend this so strongly, in fact, that Dropwizard will nag you should you neglect to add a health check to your project.
注:
我們建議如此強(qiáng)烈胰挑,事實(shí)上蔓罚,Dropwizard將會(huì)頻繁提示你應(yīng)該為你的項(xiàng)目添加健康檢查。
Since formatting strings is not likely to fail while an application is running (unlike, say, a database connection pool), we’ll have to get a little creative here. We’ll add a health check to make sure we can actually format the provided template:
由于格式化字符串在應(yīng)用程序運(yùn)行時(shí)不可能失斦八獭(不像數(shù)據(jù)庫連接池)豺谈,所以我們不得不有所創(chuàng)意。我們將增加一個(gè)健康檢查確保我們能夠格式化提供者模版:
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();
}
}
Template HealthCheckchecks for two things: that the provided template is actually a well-formed format string, and that the template actually produces output with the given name.
健康檢查做的兩件事:一是提供者模版確定能夠正確格式化字符贡这,二是模版能夠正確生產(chǎn)數(shù)據(jù)使用我們輸入的參數(shù)茬末。
If the string is not a well-formed format string (for example, someone accidentally putHello,%s%in the configuration file), thenString.format(String,Object...)will throw an IllegalFormatExceptionand the health check will implicitly fail. If the rendered saying doesn’t include the test string, the health check will explicitly fail by returning an unhealthyResult.
如果字符串不是一個(gè)格式正確的格式字符串(例如,有人不小心把配置文件中的%s%)盖矫,那么String.format(String丽惭,Object ...)將拋出一個(gè)IllegalFormatException,應(yīng)用絕對(duì)性失敗辈双。如果渲染的語句不包含測試字符串责掏,健康狀況檢查將通過返回不健康的結(jié)果而明確失敗。
Adding A Health Check
As with most things in Dropwizard, we create a new instance with the appropriate parameters and add it to the Environment:
與Dropwizard中的大多數(shù)事情一樣湃望,我們使用適當(dāng)?shù)膮?shù)創(chuàng)建一個(gè)新實(shí)例拷橘,并將其添加到環(huán)境中:
@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);
}
Now we’re almost ready to go!
現(xiàn)在我們可以準(zhǔn)備出發(fā)了!
Building Fat JARs
We recommend that you build your Dropwizard applications as “fat” JAR files — single.jar files which contain?all?of the. class files required to run your application. 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. To start building our Hello World application as a fat JAR, we need to configure a Maven plugin calledmaven-shade. In thesection of yourpom.xmlfile, add this:
我們推薦你構(gòu)建Dropwizard項(xiàng)目為一個(gè)簡單的jar包文件喜爷。jar包中包含了你項(xiàng)目所有的class文件冗疮。這使可以構(gòu)建一個(gè)可部署的jar文件,您可以從暫存環(huán)境將您的QA環(huán)境升級(jí)到生產(chǎn)環(huán)境檩帐,而無需擔(dān)心已安裝庫的差異术幔。要開始構(gòu)建我們的Hello World應(yīng)用程序jar包,我們需要配置Maven插件湃密。 在你的pom.xml文件的部分中添加:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.helloworld.HelloWorldApplication</mainClass>
</transformers>
</configuration>
</execution>
</executions>
This configures Maven to do a couple of things during its package phase:
Maven做的事情如下:
Produce a pom.xml file which doesn’t include dependencies for the libraries whose contents are included in the fat JAR.
生成一個(gè)pom.xml文件诅挑,其內(nèi)容包含在jar包中四敞。
Exclude all digital signatures from signed JARs. If you don’t, then Java considers the signature invalid and won’t load or run your JAR file.
排除jar中所有的數(shù)字標(biāo)簽。如果不這么做拔妥,Java會(huì)認(rèn)為無效不加載或者運(yùn)行jar包忿危。
Collate the various META-INF/services entries in the JARs instead of overwriting them. (Neither Dropwizard nor Jersey works without those.)
整理JAR中的各種 META-INF/services 條目而不是覆蓋它們。 (沒有這些Dropwizard和Jersey都不能工作)
Set com.example.helloworld.HelloWorldApplication as the JAR’s MainClass. This will allow you to run the JAR using java-jar.
將com.example.helloworld.HelloWorldApplication設(shè)置為Jar包的主要類没龙。將允許你使用java-jar去運(yùn)行這個(gè)jar包铺厨。
Warning
If your application has a dependency which?must?be signed (e.g., a?JCA/JCE?provider or other trusted library), you have to add an?exclusion?to the?maven-shade-plugin?configuration for that library and include that JAR in the classpath.
警告
如果您的應(yīng)用程序具有必須簽名的依賴項(xiàng)(例如,JCA / JCE提供程序或其他可信庫)硬纤,則必須為該庫的maven-shade-plugin配置添加一個(gè)排除項(xiàng)解滓,并將該JAR包含在classpath中。
Warning
Since Dropwizard is using the Java?ServiceLoader?functionality to register and load extensions, the?minimizeJaroption of the?maven-shade-plugin?will lead to non-working application JARs.
警告
由于Dropwizard使用Java ServiceLoader功能來注冊和加載擴(kuò)展筝家,maven-shade-plugin的minimizeJar選項(xiàng)將導(dǎo)致非工作的應(yīng)用程序JAR洼裤。
Versioning Your JARs
Dropwizard can also use the project version if it’s embedded in the JAR’s manifest as the Implementation-Version. To embed this information using Maven, add the following to thesection of yourpom.xmlfile:
如果你講版本潛入jar實(shí)現(xiàn)中Dropwizard項(xiàng)目可以使用項(xiàng)目版本。要使用Maven嵌入這些信息溪王,請將以下內(nèi)容添加到pom.xml文件的部分:
<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>
This can be handy when trying to figure out what version of your application you have deployed on a machine.
當(dāng)試圖找出你在一臺(tái)機(jī)器上部署的應(yīng)用程序的版本時(shí)腮鞍,這會(huì)很方便。
Once you’ve got that configured, go into your project directory and run mvn package(or run the package goal from your IDE). You should see something like this:
完成配置后莹菱,進(jìn)入項(xiàng)目目錄并運(yùn)行mvn軟件包(或從IDE運(yùn)行軟件包目標(biāo))缕减。 你應(yīng)該看到這樣的東西:
[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] ------------------------------------------------------------------------
Congratulations!You’ve built your first Dropwizard project! Now it’s time to run it!
恭喜你!你已經(jīng)完成構(gòu)建第一個(gè)Dropwizard項(xiàng)目芒珠,可以運(yùn)行了!
Running Your Application
Now that you’ve built a JAR file, it’s time to run it.
現(xiàn)在構(gòu)建一個(gè)jar文件搅裙,然后運(yùn)行它皱卓。
In your project directory, run this:
在項(xiàng)目目錄中,運(yùn)行一下命令:
java -jar target/hello-world-0.0.1-SNAPSHOT.jar
You should see something like the following:
你應(yīng)該看到以下信息:
usage: java -jar hello-world-0.0.1-SNAPSHOT.jar
? ? ? ? ? ? ? ? ? ? ? [-h] [-v] {server} ...
positional arguments:
? ? ? ? {server} ? ? ? ? ? ? ? ? ? ?available commands
optional arguments:
? ? ? -h, ? ? ? ?--help ? ? ? ? ? ? ? ? ? show this help message and exit
? ? ? -v, ? ? ? ?--version ? ? ? ? ? ? ?show the service version and exit
Dropwizard takes the first command line argument and dispatches it to a matching command. In this case, the only command available isserver, which runs your application as an HTTP server. Theservercommand requires a configuration file, so let’s go ahead and give it?the YAML file we previously saved:
Dropwizard接受第一個(gè)命令行參數(shù)并將其分派到匹配的命令部逮。 在這種情況下娜汁,唯一可用的命令是server,它作為HTTP服務(wù)器運(yùn)行你的應(yīng)用程序兄朋。 服務(wù)器命令需要一個(gè)配置文件掐禁,所以讓我們繼續(xù),并給它我們以前保存的YAML文件:
java -jar target/hello-world-0.0.1-SNAPSHOT.jar server hello-world.yml
You should see something like the following:
你應(yīng)該看到以下信息:
INFO [2011-12-03 00:38:32,927] io.dropwizard.cli.ServerCommand: Starting hello-world
INFO [2011-12-03 00:38:32,931] org.eclipse.jetty.server.Server: jetty-7.x.y-SNAPSHOT
INFO [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 STARTING
INFO [2011-12-03 00:38:33,238] org.eclipse.jetty.server.AbstractConnector: Started SocketConnector@0.0.0.0:8081 STARTING
Your Dropwizard application is now listening on ports 8080 for application requests and 8081 for administration requests. If you press ^C, the application will shut down gracefully, first closing the server socket, then waiting for in-flight requests to be processed, then shutting down the process itself.
你的Dropwizard應(yīng)用現(xiàn)在監(jiān)聽8080端口的應(yīng)用請求和8081端口上的管理請求颅和。如果你按^C組合鍵傅事,應(yīng)用將會(huì)優(yōu)雅地關(guān)閉,首先關(guān)閉服務(wù)通信峡扩,然后等待進(jìn)行中的請求執(zhí)行完畢蹭越,最后關(guān)閉進(jìn)程。
However, while it’s up, let’s give it a whirl!?Click here to say hello!Click here to get even friendlier!
但是教届,當(dāng)它出現(xiàn)的時(shí)候响鹃,讓我們來一個(gè)旋轉(zhuǎn)吧驾霜!
So, we’re generating sayings. Awesome. But that’s not all your application can do. One of the main reasons for using Dropwizard is the out-of-the-box operational tools it provides, all of which can be found?on the admin port.
我們正在產(chǎn)生sayings服務(wù)。但是买置,這不是你的應(yīng)用程序可以做的粪糙。 使用Dropwizard的主要原因之一是它提供的開箱即用的操作工具,所有這些都可以在管理端口找到忿项。
If you click through to the?metrics resource, you can see all of your application’s metrics represented as a JSON object.
如果你點(diǎn)擊查看metrics resource蓉冈,能夠看到應(yīng)用的metrics的json格式的數(shù)據(jù)。
The?threads resource?allows you to quickly get a thread dump of all the threads running in that process.
線程資源允許您快速獲取該進(jìn)程中運(yùn)行的所有線程的線程轉(zhuǎn)儲(chǔ)倦卖。
Hint
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.
暗示 當(dāng)Jetty工作線程正在處理傳入的HTTP請求時(shí)洒擦,線程名稱將被設(shè)置為請求的方法和URI。 這在調(diào)試性能不佳的請求時(shí)非常有用怕膛。
The?healthcheck resource?runs the?health check class we wrote. You should see something like this:
健康檢查資源運(yùn)行我們編寫的健康檢查類熟嫩。 你應(yīng)該看到這樣的東西:
* deadlocks: OK
* template: OK
template here is the result of your TemplateHealthCheck, which unsurprisingly passed.deadlocksis a built-in health check which looks for deadlocked JVM threads and prints out a listing if any are found.
這里的模板是您的TemplateHealthCheck的結(jié)果,毫不意外地通過褐捻。 死鎖是一個(gè)內(nèi)置的健康檢查掸茅,它會(huì)查找死鎖的JVM線程,并在找到任何列表時(shí)打印列表柠逞。
Next Steps
Well, congratulations. You’ve got a Hello World application ready for production (except for the lack of tests) that’s capable of doing 30,000-50,000 requests per second. Hopefully, you’ve gotten a feel for how Dropwizard combines Jetty, Jersey, Jackson, and other stable, mature libraries to provide a phenomenal platform for developing RESTful web applications.
那么恭喜你 您已經(jīng)準(zhǔn)備好了一個(gè)適用于生產(chǎn)的Hello World應(yīng)用程序(除了缺少測試)昧狮,它能夠每秒處理30,000-50,000個(gè)請求。 希望您已經(jīng)了解了Dropwizard如何將Jetty板壮,Jersey逗鸣,Jackson和其他穩(wěn)定,成熟的庫結(jié)合起來绰精,為開發(fā)RESTful Web應(yīng)用程序提供一個(gè)強(qiáng)大的平臺(tái)撒璧。
There’s a lot more to Dropwizard than is covered here (commands, bundles, servlets, advanced configuration, validation, HTTP clients, database clients, views, etc.), all of which is covered by the?User Manual.
Dropwizard還有很多內(nèi)容(命令,軟件包笨使,servlet卿樱,高級(jí)配置,驗(yàn)證硫椰,HTTP客戶端繁调,數(shù)據(jù)庫客戶端,視圖等)靶草,所有這些都在用戶手冊中介紹蹄胰。