很是棒的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支持監控使用標準庫,它在監控代碼方面有無與倫比的洞察力。
javascript

1. [代碼][Java]代碼     
一、配置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>
二、建立配置類
每一個Dropwizard應用程序都有一個配置類,它指定特定的環境參數。文章後面會將如主機、端口和數據庫名之類的MongoDB的配置參數添加給它。這個類擴展了 com.yammer.dropwizard.config.Configuration類。
import com.yammer.dropwizard.config.Configuration;
public class BlogConfiguration extends Configuration{
 
}
三、建立服務類
該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源加到這個方法裏。
四、寫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"));
    }
}
上面這段代碼是一個標準的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
      }
    }
  },




五、配置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();
    }
 
}
如今,更新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());
    }
 
}
上面這段代碼
使用BlogConfiguration對象建立了一個新的Mongo實例。
一個新的MongoManaged實例被建立並添加到環境中。
健康檢查被添加。javascript特效
運行該應用程序做爲主程序。你能夠到本地的 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    http://www.huiyi8.com/jiaoben/
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();
    }
}
下一步,更新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<Blog, String> 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


七、更新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;
    }
 
}
更新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));
    }
將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}]
[{"id":"527f9806300462bbd300687e","title":"Day 12: OpenCV--Face Detection for Java Developers"
java

相關文章
相關標籤/搜索