资讯专栏INFORMATION COLUMN

Day 13: Dropwizard —— 非常棒的Java REST服务器栈

Awbeci / 3083人阅读

摘要:现在可以通过点击指标检查的指标,该数据是可用的格式。健康检查被添加。现在启动,可以看到第步创建现在写类,它负责创建博客条目。为了测试,做一个请求第步更新现在,更新方法来从获取所有的博客文件。

编者注:我们发现了比较有趣的系列文章《30天学习30种新技术》,准备翻译,一天一篇更新,年终礼包。下面是第十三天的内容。

我已经是一个使用了8年Java的软件开发人员了,我写过的大多数应用程序是用的Spring框架或Java EE。最近,我花了一些时间学习用Python进行web开发,其中印象非常深刻的是 Flask 框架——一个微型架构,这使得它很容易写REST后端。所以今天我决定找一个Java的Python Flask框架替代品,做一些研究后,我发现 Dropwizard 框架可以帮助达到Flask框架同样的生产力。在这篇博客中,我们将学习如何使用Dropwizard构建一个基于REST的Java MongoDB应用程序。


什么是Dropwizard?

Dropwizard 是一个开源的Java框架,用于开发OPS友好、高性能的基于REST的后端。它是由Yammer开发的,来驱动基于JVM的后端。

Dropwizard提供同类最佳的Java库到一个嵌入式应用程序包。它由以下部分组成:

嵌入式Jetty:每一个应用程序被打包成一个jar(而不是war)文件,并开始自己的嵌入式Jetty容器。没有任何war文件和外部servlet容器。

JAX-RS:Jersey(JAX-RS的参考实现)是用来写基于REST的Web服务的。

JSON:REST服务用的是JSON,Jackson库用来做所有的JSON处理。

日志:使用Logback和SLF4J完成。

Hibernate验证:Dropwizard使用Hibernate验证API进行声明性验证。

指标:Dropwizard支持监控使用标准库,它在监控代码方面有无与伦比的洞察力。

除了上面提到的这几个,Dropwizard还使用了一些其他的库,你可以在这里找到完整的列表。


为什么是Dropwizard?

我决定学Dropwizard的原因有以下几点:

快速的项目引导:如果你已经在使用Spring和Java EE,你就会明白开发人员在引导项目时的痛苦。使用Dropwizard,你只需要在你的 pom.xml 文件中添加一个依赖就完成了。

应用指标:Dropwizard自带应用程序指标的支持。它提供了类似请求/响应时间这种非常有用的信息,只要把@ 定时注解来获取方法的执行时间。

生产力:每个Dropwizard应用程序有一个启动Jetty容器的主程序。这意味着,完全可以把应用程序作为一个主程序在IDE中运行和调试。所以就没有重新编译或部署war文件。


Github库

今天的演示应用程序的代码在GitHub上有:day13-dropwizard-mongodb-demo-app。

必备条件

基础的Java知识是必须的;

下载并安装 MongoDB数据库;

安装最新版本的Java Development Kit (JDK),OpenJDK 7 或是 Oracle JDK 7 都可以,这篇文章中使用JDK 7;

去Eclipse官网下载最新版本的Eclipse包,就目前而言eclipse最新版的代号是Kepler;

Eclipse的安装很容易,只需要解压下载下来的包即可。如果是在Linux或者Mac机器上,开个命令行窗口,输入如下命令:

$ tar -xzvf eclipse-jee-kepler-R-*.tar.gz 

Windows下,你解压到哪里,那里就会有一个eclipse文件夹,这样就可以直接操作了,当然你也可以创建执行文件的快捷方式到桌面。


第1步:创建一个新的Maven项目

打开Eclipse IDE,然后到项目工作区(project workspace)。要创建一个新的项目,转到 文件>新建> Maven项目 (File > New > Maven Project) ,然后选择 Maven 原型 - 快速启动 (maven-archetype-quickstart),然后进入Ground IdArtifact Id,最后点击“完成”。

第2步:更新pom.xml

现在更新pom.xml文件以包括dropwizard核心maven依赖。同时也将更新Maven项目使用Java 1.7版本,更新pom.xml文件后,更新Maven项目(右键单击>Maven>更新项目)


4.0.0

com.shekhar
blog
0.0.1-SNAPSHOT
jar

blog
http://maven.apache.org


    UTF-8



    
        com.yammer.dropwizard
        dropwizard-core
        0.6.2
    




    
        
            org.apache.maven.plugins
            maven-compiler-plugin
            3.1
            
                1.7
                1.7
            
        


    

第3步:创建配置类

每个Dropwizard应用程序都有一个配置类,它指定特定的环境参数。文章后面会将如主机、端口和数据库名之类的MongoDB的配置参数添加给它。这个类扩展了 com.yammer.dropwizard.config.Configuration类。

import com.yammer.dropwizard.config.Configuration;

public class BlogConfiguration extends Configuration{

}
第4步:创建服务类

该Dropwizard项目由一个服务类自举。这个类将各种提供基本功能的捆绑和命令集合在一块,它还启动嵌入式Jetty服务器并延伸com.yammer.dropwizard.Service

import com.yammer.dropwizard.Service;
import com.yammer.dropwizard.config.Bootstrap;
import com.yammer.dropwizard.config.Environment;

public class BlogService extends Service {

    public static void main(String[] args) throws Exception {
        new BlogService().run(new String[] { "server" });
    }

    @Override
    public void initialize(Bootstrap bootstrap) {
        bootstrap.setName("blog");
    }

    @Override
    public void run(BlogConfiguration configuration, Environment environment) throws Exception {

    }

}

上面的这些服务类可以:

有一个作为服务入口点的main方法。在main方法里面,创建BlogService的实例,并调用run方法。我们将服务器命令作为参数传递,服务器命令将启动嵌入式Jetty服务器。

初始化方法在服务运行方法之前被调用。

接下来,服务运行时将调用它的run方法,文章后面会将JAX-RS源加到这个方法里。

第5步:写IndexResource

写一个当GET请求指向“/” URL时会被调用的源,创建一个新的JAX-RS源(此资源将列出所有的博客),如下:

import java.util.Arrays;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.yammer.metrics.annotation.Timed;

@Path("/")
public class IndexResource {

    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    @Timed
    public List index() {
        return Arrays.asList(new Blog("Day 12: OpenCV--Face Detection for Java Developers",
                "https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers"));
    }
}

上面这段代码是一个标准的JAX-RS资源类。它添加@ Path注释和定义index()方法,这个index()会返回一个博客集合,这些博客将被转换为JSON文档。

上面提到IndexResource是用博客表示的。下面这段则表明该博客使用Hibernate验证器注解,以确保内容是有效的。例如,使用@URL注释,以确保只有合法的URL存储在MongoDB数据库。

import java.util.Date;
import java.util.UUID;

import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.URL;

public class Blog {

    private String id = UUID.randomUUID().toString();

    @NotBlank
    private String title;

    @URL
    @NotBlank
    private String url;

    private final Date publishedOn = new Date();

    public Blog() {
    }

    public Blog(String title, String url) {
        super();
        this.title = title;
        this.url = url;
    }

    public String getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public String getUrl() {
        return url;
    }

    public Date getPublishedOn() {
        return publishedOn;
    }
}

接下来,在服务类的run方法注册IndexResource。用下面的方式更新BlogService run方法。

@Override
public void run(BlogConfiguration configuration, Environment environment) throws Exception {
   environment.addResource(new IndexResource());
}

现在,可以将BlogService类​​作为一个主程序来运行(右键点击>运行方式> Java应用程序),这将启动嵌入式Jetty容器,我们可以看到程序在 http://localhost:8080/ 里运行。

$ curl http://localhost:8080

[{"id":"9bb43d53-5436-4dac-abaa-ac530c833df1","title":"Day 12: OpenCV--Face Detection for Java Developers","url":"https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers","publishedOn":1384090975372}]

现在可以通过点击“指标(Metrics)”检查IndexResource的指标,该数据是可用的JSON格式。

"com.shekhar.blog.IndexResource" : {
    "index" : {
      "type" : "timer",
      "duration" : {
        "unit" : "milliseconds",
        "min" : 17.764,
        "max" : 17.764,
        "mean" : 17.764,
        "std_dev" : 0.0,
        "median" : 17.764,
        "p75" : 17.764,
        "p95" : 17.764,
        "p98" : 17.764,
        "p99" : 17.764,
        "p999" : 17.764
      },
      "rate" : {
        "unit" : "seconds",
        "count" : 1,
        "mean" : 7.246537731991882E-4,
        "m1" : 2.290184897291144E-12,
        "m5" : 3.551918562683463E-5,
        "m15" : 2.445031498756583E-4
      }
    }
  },
第6步:配置MongoDB

pom.xml 里加入 mongo-jackson-mapper 的依赖。


    net.vz.mongodb.jackson
    mongo-jackson-mapper
    1.4.2

用MongoDB数据库的详细信息(如主机、端口和数据库名等)更新BlogConfiguration类。

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

import org.codehaus.jackson.annotate.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;

import com.yammer.dropwizard.config.Configuration;

public class BlogConfiguration extends Configuration {

    @JsonProperty
    @NotEmpty
    public String mongohost = "localhost";

    @JsonProperty
    @Min(1)
    @Max(65535)
    public int mongoport = 27017;

    @JsonProperty
    @NotEmpty
    public String mongodb = "mydb";
}

接下来,创建一个名为MongoManaged的新类,它将允许你在应用程序启动和停止时管理程序资源。这样就实现了com.yammer.dropwizard.lifecycle.Managed

import com.mongodb.Mongo;
import com.yammer.dropwizard.lifecycle.Managed;

public class MongoManaged implements Managed {

    private Mongo mongo;

    public MongoManaged(Mongo mongo) {
        this.mongo = mongo;
    }

    @Override
    public void start() throws Exception {
    }

    @Override
    public void stop() throws Exception {
        mongo.close();
    }

}

在上面的代码中,关闭了stop方法中的MongoDB连接。

下一步,写一个MongoHealthCheck来检查MongoDB的连接与否。

import com.mongodb.Mongo;
import com.yammer.metrics.core.HealthCheck;

public class MongoHealthCheck extends HealthCheck {

    private Mongo mongo;

    protected MongoHealthCheck(Mongo mongo) {
        super("MongoDBHealthCheck");
        this.mongo = mongo;
    }

    @Override
    protected Result check() throws Exception {
        mongo.getDatabaseNames();
        return Result.healthy();
    }
}

现在,更新BlogService类​​,将MongoDB的配置包含进来。

package com.shekhar.blog;

import com.mongodb.Mongo;
import com.yammer.dropwizard.Service;
import com.yammer.dropwizard.config.Bootstrap;
import com.yammer.dropwizard.config.Environment;

public class BlogService extends Service {

    public static void main(String[] args) throws Exception {
        new BlogService().run(new String[] { "server" });
    }

    @Override
    public void initialize(Bootstrap bootstrap) {
        bootstrap.setName("blog");
    }

    @Override
    public void run(BlogConfiguration configuration, Environment environment) throws Exception {
        Mongo mongo = new Mongo(configuration.mongohost, configuration.mongoport);
        MongoManaged mongoManaged = new MongoManaged(mongo);
        environment.manage(mongoManaged);

        environment.addHealthCheck(new MongoHealthCheck(mongo));

        environment.addResource(new IndexResource());
    }
}

上面这段代码:

使用BlogConfiguration对象创建了一个新的Mongo实例。

一个新的MongoManaged实例被创建并添加到环境中。

健康检查被添加。

运行该应用程序作为主程序。你可以到本地的 http://localhost:8081/healthcheck 健康检查页面去检验MongoDB是否在运行,如果MongoDB没有运行,会看到一个异常堆栈跟踪。

! MongoDBHealthCheck: ERROR
!  can"t call something : Shekhars-MacBook-Pro.local/192.168.1.101:27017/admin

com.mongodb.MongoException$Network: can"t call something : Shekhars-MacBook-Pro.local/192.168.1.101:27017/admin
    at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:227)
    at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:305)
    at com.mongodb.DB.command(DB.java:160)
    at com.mongodb.DB.command(DB.java:183)
    at com.mongodb.Mongo.getDatabaseNames(Mongo.java:327)
    at com.shekhar.blog.MongoHealthCheck.check(MongoHealthCheck.java:17)
    at com.yammer.metrics.core.HealthCheck.execute(HealthCheck.java:195)
    at 
Caused by: java.io.IOException: couldn"t connect to [Shekhars-MacBook-Pro.local/192.168.1.101:27017] bc:java.net.ConnectException: Connection refused
    at com.mongodb.DBPort._open(DBPort.java:228)
    at com.mongodb.DBPort.go(DBPort.java:112)
    at com.mongodb.DBPort.call(DBPort.java:79)
    at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:218)
    ... 33 more

* deadlocks: OK

现在启动MongoDB,可以看到:

* MongoDBHealthCheck: OK
* deadlocks: OK
第7步:创建BlogResource

现在写BlogResource类,它负责创建博客条目。

import java.util.ArrayList;
import java.util.List;

import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import net.vz.mongodb.jackson.DBCursor;
import net.vz.mongodb.jackson.JacksonDBCollection;

import com.yammer.metrics.annotation.Timed;

@Path("/blogs")
@Produces(value = MediaType.APPLICATION_JSON)
@Consumes(value = MediaType.APPLICATION_JSON)
public class BlogResource {

    private JacksonDBCollection collection;

    public BlogResource(JacksonDBCollection blogs) {
        this.collection = blogs;
    }

    @POST
    @Timed
    public Response publishNewBlog(@Valid Blog blog) {
        collection.insert(blog);
        return Response.noContent().build();
    }
}

下一步,更新BlogService run方法,将BlogResource也加进来。

 @Override
    public void run(BlogConfiguration configuration, Environment environment) throws Exception {
        Mongo mongo = new Mongo(configuration.mongohost, configuration.mongoport);
        MongoManaged mongoManaged = new MongoManaged(mongo);
        environment.manage(mongoManaged);

        environment.addHealthCheck(new MongoHealthCheck(mongo));

        DB db = mongo.getDB(configuration.mongodb);
        JacksonDBCollection blogs = JacksonDBCollection.wrap(db.getCollection("blogs"), Blog.class, String.class);

        environment.addResource(new IndexResource());

        environment.addResource(new BlogResource(blogs));
    }

将BlogService类作为一个Java应用程序运行。为了测试BlogResource,做一个curl请求:

$ curl -i -X POST -H "Content-Type: application/json" -d "{"title":"Day 12: OpenCV--Face Detection for Java Developers","url":"https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers"}" http://localhost:8080/blogs


HTTP/1.1 204 No Content
Date: Sun, 10 Nov 2013 14:08:03 GMT
Content-Type: application/json
第8步:更新IndexResource

现在,更新IndexResource index()方法来从MongoDB获取所有的博客文件。

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import net.vz.mongodb.jackson.DBCursor;
import net.vz.mongodb.jackson.JacksonDBCollection;

import com.yammer.metrics.annotation.Timed;

@Path("/")
public class IndexResource {

    private JacksonDBCollection collection;

    public IndexResource(JacksonDBCollection blogs) {
        this.collection = blogs;
    }

    @GET
    @Produces(value = MediaType.APPLICATION_JSON)
    @Timed
    public List index() {
        DBCursor dbCursor = collection.find();
        List blogs = new ArrayList<>();
        while (dbCursor.hasNext()) {
            Blog blog = dbCursor.next();
            blogs.add(blog);
        }
        return blogs;
    }

}

更新BlogService run方法将博客集合传递给IndexResource。

@Override
    public void run(BlogConfiguration configuration, Environment environment) throws Exception {
        Mongo mongo = new Mongo(configuration.mongohost, configuration.mongoport);
        MongoManaged mongoManaged = new MongoManaged(mongo);
        environment.manage(mongoManaged);

        environment.addHealthCheck(new MongoHealthCheck(mongo));

        DB db = mongo.getDB(configuration.mongodb);
        JacksonDBCollection blogs = JacksonDBCollection.wrap(db.getCollection("blogs"), Blog.class, String.class);

        environment.addResource(new IndexResource(blogs));

        environment.addResource(new BlogResource(blogs));
    }

将BlogService类作为一个Java应用程序运行。为了测试BlogResource,做一个curl请求:

$ curl http://localhost:8080

[{"id":"527f9806300462bbd300687e","title":"Day 12: OpenCV--Face Detection for Java Developers","url":"https://www.openshift.com/blogs/day-12-opencv-face-detection-for-java-developers","publishedOn":1384093702592}]
第9步:部署到云端

这里有一篇文章,教你如何在OpenShift部署Dropwizard应用,点击这里。



今天就这些,欢迎反馈。


原文 Day 13: Dropwizard--The Awesome Java REST Server Stack
整理 SegmentFault

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/63989.html

相关文章

  • 的确,Java存在缺陷。但是……

    摘要:是当时唯一的书,而且只有语言规范。仍然在中使用未来可能被取代,但不是现在。仍然是大学里教授的主要语言,并且存在于很多优秀的库中,比如。笔者期待积极的讨论。的确存在缺陷,但这些缺陷并不妨碍它在世界上最主要的公司和系统内全天候地完成工作。 【编者按】本文作者为资深码农 Tim Spann,主要讲述 Java 让人无法抗拒的众多优点以及一些些缺陷。本文系国内 ITOM 管理平台 OneAPM...

    wayneli 评论0 收藏0
  • Day 4:PredictionIO——如何创建一个博客推荐器

    摘要:是什么是一个用编写的开源机器学习服务器应用,可以帮助你方便地使用搭建推荐引擎。是一个可伸缩的机器学习库,它提供众多聚集分类过滤算法。我为什么要关心我决定学习是因为我想使用一个可以帮助我加上机器学习功能的库。 编者注:我们发现了比较有趣的系列文章《30天学习30种新技术》,准备翻译,一天一篇更新,年终礼包。下面是第四天的内容。 今天是30天学习30种新技术的第4天。到目前为止我很享...

    tinysun1234 评论0 收藏0
  • Day 4:PredictionIO——如何创建一个博客推荐器

    摘要:是什么是一个用编写的开源机器学习服务器应用,可以帮助你方便地使用搭建推荐引擎。是一个可伸缩的机器学习库,它提供众多聚集分类过滤算法。我为什么要关心我决定学习是因为我想使用一个可以帮助我加上机器学习功能的库。 编者注:我们发现了比较有趣的系列文章《30天学习30种新技术》,准备翻译,一天一篇更新,年终礼包。下面是第四天的内容。 今天是30天学习30种新技术的第4天。到目前为止我很享...

    bbbbbb 评论0 收藏0
  • Day 17: 使用 JBoss Forge 和 OpenShift 构建部署 JAVA EE 6

    摘要:会警告该插件未签名。以上命令告诉创建一个名为的项目,使用包。的工具使从部署应用非常方便。域名构成了分配给应用的的一部分。这将为我们创建一个应用容器,自动配置和。同时将创建一个私有的仓库并克隆到本地。 编者注:我们发现了有趣的系列文章《30天学习30种新技术》,正在翻译,一天一篇更新,年终礼包。下面是第 17 天的内容。 今天的30天学习30种新技术挑战,我决定学习一下JBoss ...

    YacaToy 评论0 收藏0
  • [译] 唯快不破:Web 应用的 13 个优化步骤

    摘要:译文地址译唯快不破应用的个优化步骤前端的逆袭知乎专栏原文地址时过境迁,应用比以往任何时候都更具交互性。使用负载均衡方案我们在之前讨论缓存的时候简要提到了内容分发网络。换句话说,元素的串形访问会削弱负载均衡器以最佳形式 欢迎关注知乎专栏 —— 前端的逆袭欢迎关注我的博客,知乎,GitHub。 译文地址:【译】唯快不破:Web 应用的 13 个优化步骤 - 前端的逆袭 - 知乎专栏原文地...

    haobowd 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<