Introduction to Dropwizard – Dropwizard简介

最后修改: 2020年 1月 28日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Dropwizard is an open-source Java framework used for the fast development of high-performance RESTful web services. It gathers some popular libraries to create the light-weight package. The main libraries that it uses are Jetty, Jersey, Jackson, JUnit, and Guava. Furthermore, it uses its own library called Metrics.

Dropwizard是一个开源的Java框架,用于快速开发高性能的RESTful Web服务。它收集了一些流行的库来创建轻量级的包。它使用的主要库是Jetty、Jersey、Jackson、JUnit和Guava。此外,它还使用了自己的库,称为Metrics>。

In this tutorial, we’ll learn how to configure and run a simple Dropwizard application. When we’re done, our application will expose a RESTful API that allows us to obtain a list of stored brands.

在本教程中,我们将学习如何配置和运行一个简单的Dropwizard应用程序。当我们完成后,我们的应用程序将暴露一个RESTful API,允许我们获得一个存储品牌的列表。

2. Maven Dependencies

2.Maven的依赖性

Firstly, the dropwizard-core dependency is all we need in order to create our service. Let’s add it to our pom.xml:

首先,dropwizard-core依赖性是我们创建服务所需要的。让我们把它添加到我们的pom.xml中。

<dependency>
    <groupId>io.dropwizard</groupId>
    <artifactId>dropwizard-core</artifactId>
    <version>2.0.0</version>
</dependency>

3. Configuration

3.配置

Now, we’ll create the necessary classes that are needed for every Dropwizard application to run.

现在,我们将创建每个Dropwizard应用程序运行所需的必要类。

Dropwizard applications store properties in YML files. Therefore, we’ll create the introduction-config.yml file in the resource directory:

Dropwizard应用程序在YML文件中存储属性。因此,我们将在资源目录中创建introduction-config.yml文件。

defaultSize: 5

We can access values in that file by creating a class that extends io.dropwizard.Configuration:

我们可以通过创建一个扩展io.dropwizard.Configuration的类来访问该文件中的值。

public class BasicConfiguration extends Configuration {
    @NotNull private final int defaultSize;

    @JsonCreator
    public BasicConfiguration(@JsonProperty("defaultSize") int defaultSize) {
        this.defaultSize = defaultSize;
    }

    public int getDefaultSize() {
        return defaultSize;
    }
}

Dropwizard uses Jackson to deserialize the configuration file into our class. Hence, we’ve used Jackson annotations.

Dropwizard使用Jackson来将配置文件反序列化到我们的类中。因此,我们使用了Jackson注解。

Next, let’s create the main application class, which is responsible for preparing our service for usage:

接下来,让我们创建主应用程序类,它负责为我们的服务做好使用准备。

public class IntroductionApplication extends Application<BasicConfiguration> {

    public static void main(String[] args) throws Exception {
        new IntroductionApplication().run("server", "introduction-config.yml");
    }

    @Override
    public void run(BasicConfiguration basicConfiguration, Environment environment) {
        //register classes
    }

    @Override
    public void initialize(Bootstrap<BasicConfiguration> bootstrap) {
        bootstrap.setConfigurationSourceProvider(new ResourceConfigurationSourceProvider());
        super.initialize(bootstrap);
    }
}

Firstly, the main method is responsible for running the application. We could either pass the args to the run method or fill it by ourselves.

首先,main方法负责运行应用程序。我们可以将args传递给run方法,或者自己填充。

The first argument can be either server or check. The check option validates the configuration, while the server option runs the application. The second argument is the location of the configuration file. 

第一个参数可以是servercheck check选项验证配置,而server选项运行应用程序。第二个参数是配置文件的位置。

Furthermore, the initialize method sets the configuration provider to the ResourceConfigurationSourceProvider, which allows the application to find a given configuration file in the resource directory. It isn’t obligatory to override this method.

此外,initialize方法将配置提供者设置为ResourceConfigurationSourceProvider,这使得应用程序能够在资源目录中找到一个给定的配置文件。覆盖这个方法并不是必须的。

Lastly, the run method allows us to access both the Environment and the BaseConfiguration, which we’ll use later in this article.

最后,run方法允许我们同时访问EnvironmentBaseConfiguration,我们将在本文后面使用。

4. Resource

4.资源

Firstly, let’s create a domain class for our brand:

首先,让我们为我们的品牌创建一个域类。

public class Brand {
    private final Long id;
    private final String name;

    // all args constructor and getters
}

Secondly, let’s create a BrandRepository class that’ll be responsible for returning brands:

其次,让我们创建一个BrandRepository类,它将负责返回品牌。

public class BrandRepository {
    private final List<Brand> brands;

    public BrandRepository(List<Brand> brands) {
        this.brands = ImmutableList.copyOf(brands);
    }

    public List<Brand> findAll(int size) {
        return brands.stream()
          .limit(size)
          .collect(Collectors.toList());
    }

    public Optional<Brand> findById(Long id) {
        return brands.stream()
          .filter(brand -> brand.getId().equals(id))
          .findFirst();
    }
}

Additionally, we were able to use the ImmutableList from Guava because it’s part of Dropwizard itself.

此外,我们能够使用Guava中的ImmutableList ,因为它是Dropwizard本身的一部分。

Thirdly, we’ll create a BrandResource class. The Dropwizard uses JAX-RS by default with Jersey as implementation. Therefore, we’ll make use of annotations from this specification to expose our REST API endpoints:

第三,我们将创建一个BrandResource类。Dropwizard默认使用JAX-RS,Jersey作为实现。因此,我们将利用该规范的注解来暴露我们的REST API端点。

@Path("/brands")
@Produces(MediaType.APPLICATION_JSON)
public class BrandResource {
    private final int defaultSize;
    private final BrandRepository brandRepository;

    public BrandResource(int defaultSize, BrandRepository brandRepository) {
        this.defaultSize = defaultSize;
        this.brandRepository = brandRepository;
    }

    @GET
    public List<Brand> getBrands(@QueryParam("size") Optional<Integer> size) {
        return brandRepository.findAll(size.orElse(defaultSize));
    }

    @GET
    @Path("/{id}")
    public Brand getById(@PathParam("id") Long id) {
        return brandRepository
          .findById(id)
          .orElseThrow(RuntimeException::new);
    }
}

Additionally, we’ve defined size as Optional in order to use defaultSize from our configuration if the argument is not provided.

此外,我们将size定义为Optional,以便在没有提供参数的情况下使用我们配置中的defaultSize

Lastly, we’ll register BrandResource in the IntroductionApplicaton class. In order to do that, let’s implement the run method:

最后,我们将在IntroductionApplicaton类中注册BrandResource。为了做到这一点,让我们实现run方法。

@Override
public void run(BasicConfiguration basicConfiguration, Environment environment) {
    int defaultSize = basicConfiguration.getDefaultSize();
    BrandRepository brandRepository = new BrandRepository(initBrands());
    BrandResource brandResource = new BrandResource(defaultSize, brandRepository);

    environment
      .jersey()
      .register(brandResource);
}

All created resources should be registered in this method.

所有创建的资源都应在此方法中注册。

5. Running Application

5.运行应用程序

In this section, we’ll learn how to run the application from the command line.

在本节中,我们将学习如何从命令行中运行该应用程序。

First, we’ll configure our project to build a JAR file using the maven-shade-plugin:

首先,我们要配置我们的项目,使用maven-shad-plugin构建一个JAR文件。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <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.baeldung.dropwizard.introduction.IntroductionApplication</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

This is the suggested configuration of the plugin. Additionally, we’ve included the path to our main class in the <mainClass> element.

这是该插件的建议配置。此外,我们在<mainClass>元素中包含了我们主类的路径。

Finally, we’ll build the application with Maven. Once we have our JAR file, we can run the application:

最后,我们将用Maven构建该应用程序。一旦我们有了JAR文件,我们就可以运行该应用程序。

java -jar target/dropwizard-0.0.1-SNAPSHOT.jar

There’s no need to pass the parameters because we’ve already included them in the IntroductionApplication class.

没有必要传递参数,因为我们已经在IntroductionApplicationclass中包含了这些参数。

After that, the console log should end with:

之后,控制台日志应该以以下内容结束。

INFO  [2020-01-08 18:55:06,527] org.eclipse.jetty.server.Server: Started @1672ms

Now, the application is listening on port 8080, and we can access our brand endpoint at http://localhost:8080/brands.

现在,应用程序正在监听8080端口,我们可以在http://localhost:8080/brands上访问我们的品牌终端。

6. Health Check

6.健康检查

When starting the application, we were informed that the application doesn’t have any health checks. Fortunately, Dropwizard provides an easy solution to add health checks to our application.

当启动该应用程序时,我们被告知该应用程序没有任何健康检查。幸运的是,Dropwizard提供了一个简单的解决方案来为我们的应用程序添加健康检查

Let’s start by adding a simple class that extends com.codahale.metrics.health.HealthCheck:

让我们从添加一个简单的类开始,它扩展了com.codahale.metrics.health.HealthCheck

public class ApplicationHealthCheck extends HealthCheck {
    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
}

This simple method will return information about the healthiness of our component. We could create multiple health checks, and some of them might fail in certain situations. For instance, we would return Result.unhealthy() if the connection to the database failed.

这个简单的方法将返回关于我们组件的健康状况的信息。我们可以创建多个健康检查,其中一些可能在某些情况下失败。例如,如果与数据库的连接失败,我们将返回Result.unhealthy()

Lastly, we need to register our health check in the run method of our IntroductionApplication class:

最后,我们需要在IntroductionApplication类的run方法中注册我们的健康检查

environment
  .healthChecks()
  .register("application", new ApplicationHealthCheck());

After running the application, we can check the health check response under http://localhost:8081/healthcheck:

运行应用程序后,我们可以在http://localhost:8081/healthcheck检查健康检查响应

{
  "application": {
    "healthy": true,
    "duration": 0
  },
  "deadlocks": {
    "healthy": true,
    "duration": 0
  }
}

As we can see, our health check has been registered under the application tag.

我们可以看到,我们的健康检查已经在application标签下注册。

7. Conclusion

7.结语

In this article, we’ve learned how to set up the Dropwizard application with Maven.

在这篇文章中,我们已经学会了如何用Maven设置Dropwizard应用程序。

We’ve discovered that the base setup of the application is really easy and fast. Additionally, Dropwizard includes every library that we need to run the high-performance RESTful web service.

我们发现,应用程序的基本设置真的很容易和快速。此外,Dropwizard包括每一个我们需要运行高性能RESTful网络服务的库。

As always, the code for these examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到over