1.关于Dropwizard的一些闲扯
在我的上一篇博客《 Embedded Server:像写main函数一样写Web Server》中,提到了使用Jetty Embedded Server进行 Server的开发比传统的Web 的方式进行开发的优势。如果直接使用Jetty提供的API进行Web Server的开发,特别是RESTful service的开发,难免看起来还是简单粗暴了一些。
然后期望着更多的程序员逃离java世界,奔向看起来很美好的Ruby, Python等等。我自己而言,我不关心java是不是已经死在沙滩上了,更多的是想,新语言引入的新的技术,或者一些新的思潮,能够折射出我们Java语言或者开发环境中的哪些不足。
有很多用Ruby on Rails的人,在对ruby知之甚少的情况下,就开始吭哧吭哧的写Server了。Rails提供了开发一个Server的完整技术栈,可以很方便的进行开发,后来又有很多人提供了很多RoR的的插件。
Dropwizard也是这么一个东西,提供了使用Java进行RESTful开发的所需要的最小的技术集合,使用了最轻量级的library。如之前博客里提到的Jetty,还有Jersey,Jackson等等。在Dropwizard官网上对其自身的介绍还是比较客气的,不过看了Dropwizard在github上(https://github.com/dropwizard/dropwizard)的介绍还是更来的实际些:
A damn simple library for building production-ready RESTful web services.
一个damn是那么的霸气侧漏。也希望有一天我开发的某个library或者框架也能用上这样的词语:RNM,TTMD等等。
2. 启动Dropwizard编译生成的Server
在真正介绍如何使用Dropwizard之前,我想先让大家看看如何运行已经写好的Server的:
java -jar dropwizard-demo-standalone.jar server hello.yaml
这样做的原因,是让大家知道这个东西用起来很简单,这让我自己更迫不及待的想要用它。
3. 使用Dropwizard写一个RESTful Service
用Dropwizard写一个RESTful Service至少需要这么几个部分:一是Configuration,二是Service,然后是Resource。因为Dropwizard中已经包括了最常用和最好用的几个开源库,这样编写一个Service会方便和快捷很多。Configuration主要是作为Serivce本身的配置,通过Service可以访问对应的Resource。下面就看一个简单的例子:
Configuration:
Configuration用于从配置文件中读取信息,比如从前面的hello.yaml中读取。Dropwizard中默认的是使用yaml,当你提供的配置文件的后缀名不是.yml或者.yaml时,将会讲你的配置文件看做JSON格式。
hello.yaml
template: Hello, %s!
defaultName: Stranger在hello.yaml中提供了两个属性,template和defaultName。对应的是Java中的HelloConfiguration:
public class HelloConfiguration extends Configuration { @NotEmpty@JsonProperty private String template;
@NotEmpty @JsonProperty private String defaultName = "Stranger"; public String getDefaultName() { return defaultName; } public String getTemplate() { return template; }}
Service:
public class HelloService extends Service<HelloConfiguration> { public static void main(String[] args) throws Exception { new HelloService().run(args); } @Override public void initialize(Bootstrap<HelloConfiguration> bootstrap) { bootstrap.setName("hello"); } @Override public void run(HelloConfiguration configuration, Environment environment) throws Exception { final String template = configuration.getTemplate(); final String defaultName = configuration.getDefaultName(); environment.addResource(new HelloResource(template, defaultName)); }}
在service中比较关键的几个东西包括HelloConfiguration,这个就是我们先前从hello.yaml中解析出的对象。还有就是Environment,Dropwizard提供了很多组件,包括像Resource, Filter, HealthCheck等等,这些都被包括在了environment中。这里我们添加了一个HelloResource。
Resource:
@Path("hello")
@Produces(MediaType.APPLICATION_JSON)public class HelloResource { private final String template; private final String defaultName; private final AtomicLong counter; public HelloResource(String template, String defaultName) { this.template = template; this.defaultName = defaultName; this.counter = new AtomicLong(); } @GET public Saying sayHello(@QueryParam("name") Optional<String> name) { return new Saying(counter.incrementAndGet(), String.format(template, name.or(defaultName))); }}public class Saying {
private final long id; private final String content; public Saying(long id, String content) { this.id = id; this.content = content; } public long getId() { return id; } public String getContent() { return content; }}3. 验证Service
在服务被启动起来以后,我们可以验证:
curl http://localhost:8080/?hello=gogo
返回:
{"id":1,"content":"Hello, kiwi!"}
4. 更多
博客中用到的例子其实都出自Dropwizard的官网,希望大家不要嫌弃我。这里把例子几乎完整的列出来的原因是在于,想展示给大家使用Dropwizard可以很方便的开发一个RESTful Service。特别是对于小型的Service,使用Dropwizard进行开发就显得极其方便。也许有人要说,大型的Service怎么办呢?我的系统或者业务本身就是很复杂怎么办呢?是不是就不能用Embedded Server了?是不是就不能用Dropwizard提供的生态系统了?其实不然,当然这里面有更多的巧思。另外,Dropwizard中还有很多有意思而且好用的组件。