首页 > 代码库 > 非常棒的Java REST服务器栈
非常棒的Java REST服务器栈
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支持监控使用标准库,它在监控代码方面有无与伦比的洞察力。
1. [代码][Java]代码
1、配置maven以导入jar包。
<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>
2、创建配置类
每个Dropwizard应用程序都有一个配置类,它指定特定的环境参数。文章后面会将如主机、端口和数据库名之类的MongoDB的配置参数添加给它。这个类扩展了 com.yammer.dropwizard.config.Configuration类。
?import com.yammer.dropwizard.config.Configuration;
public class BlogConfiguration extends Configuration{
}
3、创建服务类
该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 {
}
}
上面的这些服务类可以:
有一个作为服务入口点的main方法。在main方法里面,创建BlogService的实例,并调用run方法。我们将服务器命令作为参数传递,服务器命令将启动嵌入式Jetty服务器。
初始化方法在服务运行方法之前被调用。
接下来,服务运行时将调用它的run方法,文章后面会将JAX-RS源加到这个方法里。
4、写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 = http://www.mamicode.com/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"));
}
}
上面这段代码是一个标准的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}]
The administrative interface is available at http://localhost:8081/.
现在可以通过点击“指标(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
}
}
},
5、配置MongoDB
在pom.xml 里加入 mongo-jackson-mapper 的依赖。
<dependency>
<groupId>net.vz.mongodb.jackson</groupId>
<artifactId>mongo-jackson-mapper</artifactId>
<version>1.4.2</version>
</dependency>
用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();
}
}