设为首页 收藏本站
查看: 2052|回复: 0

[经验分享] [译] 第十三天:Dropwizard

[复制链接]

尚未签到

发表于 2017-2-28 10:26:46 | 显示全部楼层 |阅读模式
前言
  在8年软件开发生涯中我俨然一位Java开发者了。大多数我写的程序,都用Spring框架或者Java EE.最近我在学Python Web开发,其中印象很深的一个是Flask框架。Flask框架是个微框架,使得写REST后端很简单。我今天的30天挑战,决定找一款Java框架替代Python的Flask。一番搜索后,我发现Dropwizard框架可以达到如Flask同样的功效。这篇博客,我们来学习怎样用Dropwizard构建RESTful Java MongoDB程序。
   DSC0000.png

什么是Dropwizard?
  Dropwizard是一款开源Java框架,用于ops友好开发,高性能RESTful后端开发。它由Yammer开发并提供基于JVM后端的支持。
  Dropwizar延续最优Java库,嵌入到程序包,包括以下组件:


  • 嵌入Jetty: 每个程序都打包成jar而不是war,启用自带的Jetty容器,没有WAR文件也没有外部servlet容器。
  • JAX-RS:      Jersey(JAX-RS的参考实现)用来写RESTful Web服务,这样就没白费你已懂的JAX-RS知识。
  • JSON: REST服务使用JSON, Jackson库用来做所有JSON处理。
  • Logging: 用Logback和SLF4J完成。
  • Hibernate      Validator: Dropwizard用Hbernate Vlidator API来验证声明。
  • Metrics:      Dropwizard支持用Metrics库进行检测,提供观察代码对生产做了什么的绝佳视觉。

为什么选择Dropwizard?
  我学习Dropwizard的几点原因:


  • 快速的项目引导:要是你用过Spring或者Java EE, 就会了解开发者要通过项目引导的痛苦,用Dropwizard,只需要添加一个依赖到pom.xml文件就好了。
  • 项目Metrics:      Dropwizard支持项目metrics, 它提供很有用的信息如请求/相应时间等,我们只需给出@Timed注解就可获得方法执行时间。
  • 生产力:每个Dropwizard应用有一个启用Jetty容器的主程序,意味着可以在IDE里直接像主程序一样运行和调试,没有必要再编译或者部署WAR文件。

Github仓库
  今天的demo放在github: day13-dropwizard-mongodb-demo-app.

前提准备


  • 必须会Java基础。
  • 下载和安装MongoDB数据库。
  • 安装最新Java Development      Kit(JDK), 可以装OpenJDK7或者Oracle JDK 7. OpenShift支持OpenJDK 6和7, 这篇博客,我们用JDK 7.
  • 从官网下载最新的Eclipse,目前最新版本是Kepler.
DSC0001.png

  安装Eclipse很简单,只需解压下载的安装包。在linux或者mac上,打开命令管理器输入以下命令。



$ tar -xzvf eclipse-jee-kepler-R-*.tar.gz
  Windows上可以用7-zip或者其他解压工具解压,解压后,在你解压的路径会有一个eclipse的文件夹,可以给可执行文件创建快捷键。

第一步:新建Maven项目
  打开Eclipse IDE导航到项目空间,新建项目,到File > New > Maven Project,选择maven-archetype-quichstart,输入Ground Id和Artifact Id,最后点Finish.
   DSC0002.png

第二步:更新pom.xml
  现在更新pom.xml, 加入dropwizard-core maven依赖,再更新Maven项目用Java 1.7版本,更新pom.xml后更新Maven项目(右击>Maven>Update Project)


DSC0003.gif DSC0004.gif


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shekhar</groupId>
<artifactId>blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>blog</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.yammer.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
<version>0.6.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>

</plugins>
</build>
</project>
View Code
第三步:创建配置类
  每个Dropwizard程序都有一个配置类,用来指定特定环境变量。后面我们会添加MongoDB配置参数如host, port, db name.这个类继承com.yammer.dropwizard.config.Configuration。





import com.yammer.dropwizard.config.Configuration;
public class BlogConfiguration extends Configuration{
}
View Code
第四步:创建服务类
  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<BlogConfiguration> {
public static void main(String[] args) throws Exception {
new BlogService().run(new String[] { "server" });
}
@Override
public void initialize(Bootstrap<BlogConfiguration> bootstrap) {
bootstrap.setName("blog");
}
@Override
public void run(BlogConfiguration configuration, Environment environment) throws Exception {
}
}
View Code 以上代码做了以下动作:


  • 这个类有一个主方法,作为服务的入口,在这个主方法里,创建了一个BlogService实例来调用run方法,server命令用参数形式传递,它会启动内嵌的Jetty服务。
  • Initalize 方法在执行service run方法前调用,设置服务名为blog.
  • 接下来,有一个run方法会在service运行时调用,后面,我们会添加JAX-RS资源到这个方法。

第五步:写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<Blog> 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"));
}
}
View Code   以上代码是一个标准的JAX-RS资源类,注释了@Path,定义了index()方法。Index()返回博客的集合,这些博客会被转换成JSON文档,@Timed注释确定了Dropwizard基础时间。
  以上IndexResource用一篇博客呈现,显示如下,博客的呈现用hibernate validator注释来确保内容有效性。例如,用@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;
}
}
View Code   然后,在service类run方法里注册IndexResource, 用以下代码更新BlogService的run方法。





@Override
public void run(BlogConfiguration configuration, Environment environment) throws Exception {
environment.addResource(new IndexResource());
}
View Code   现在我们可以把BlogService作为主程序运行,右击>Run As>Java Application. 会启动内嵌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}]
管理界面在http://localhost:8081/
  点击Metrics可以查看IndexResource的Metricx, 数据是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
}
}
},
View Code
第六步:配置MongoDB
  在pom.xml里添加Mongo-jackson-mapper依赖。





<dependency>
<groupId>net.vz.mongodb.jackson</groupId>
<artifactId>mongo-jackson-mapper</artifactId>
<version>1.4.2</version>
</dependency>
View Code   更新BlogConfiguration类的MongoDB数据库信息,如host, port, database name.





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";
}
View Code   接下来新建一个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();
}

}
View Code   以上代码,我们在Stop方法里关掉MongoDB连接。

  接下来我们创建一个MongoHealthCheck来检查MongoDB是连接还是断开的,Health check是Dropwizard在生产环境做执行时测试检测服务的行为的功能。





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();
}
}
View Code   现在更新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<BlogConfiguration> {
public static void main(String[] args) throws Exception {
new BlogService().run(new String[] { "server" });
}
@Override
public void initialize(Bootstrap<BlogConfiguration> 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());
}
}
View Code
以上代码:


  • 用BlogConfiguration对象新建了一个Mongo实例。
  • 新建了MongoManaged实例并添加到环境中。
  • 添加了正常检测。


  以主程序运行应用,可以通过http://localhost:8081/healthcheck的HealthCheck页面检测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
第七步:创建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<Blog, String> collection;
public BlogResource(JacksonDBCollection<Blog, String> blogs) {
this.collection = blogs;
}
@POST
@Timed
public Response publishNewBlog(@Valid Blog blog) {
collection.insert(blog);
return Response.noContent().build();
}
}
View Code   用Java程序类型运行BlogService类,要测试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
第八步:更新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<Blog, String> collection;
public IndexResource(JacksonDBCollection<Blog, String> blogs) {
this.collection = blogs;
}
@GET
@Produces(value = MediaType.APPLICATION_JSON)
@Timed
public List<Blog> index() {
DBCursor<Blog> dbCursor = collection.find();
List<Blog> blogs = new ArrayList<>();
while (dbCursor.hasNext()) {
Blog blog = dbCursor.next();
blogs.add(blog);
}
return blogs;
}
}
View Code   更新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<Blog, String> blogs = JacksonDBCollection.wrap(db.getCollection("blogs"), Blog.class, String.class);
environment.addResource(new IndexResource(blogs));
environment.addResource(new BlogResource(blogs));
}
View Code   用Java程序形式运行BlogService, 要测试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}]
第九步:发布到云
  这有一个博客讲我们怎样发布Dropwizard程序到OpenShift, 参考博客。
这是今天的内容,继续给反馈吧。
原文:https://www.openshift.com/blogs/day-13-dropwizard-the-awesome-java-rest-server-stack

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-348305-1-1.html 上篇帖子: maven入门详解 下篇帖子: 用Java开发gRPC服务的例子分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表