您的位置:首页 > 运维架构 > 网站架构

REST微服务架构之Dropwizard

2016-05-03 00:00 423 查看
摘要: DropWizard是由Yammer开发团队贡献的一个后台服务开发框架,其集成了Java生态系统中各个问题域中最优秀的组件,帮助开发者快速的打造一个Rest风格的后台服务。

一、简介

DropWizard是由Yammer开发团队贡献的一个后台服务开发框架,其集成了Java生态系统中各个问题域中最优秀的组件,帮助开发者快速的打造一个Rest风格的后台服务。

对开发者来说,使用DropWizard有如下好处:
1、和Maven集成良好,也就是说和Gradle集成也很良好;
2、开发迅速,部署简单;
3、代码结构好,可读性高;
4、自动为服务提供OM框架;
5、让开发者自然的把一个应用拆分为一个个的小服务

DropWizard结构的Web服务组成
1、Configuration:用于设置该服务的配置,比方说在服务开放在哪个端口,数据库配置是怎样的等等。
2、Application(即Service):该服务的主入口,定义该服务使用哪个配置文件,开放哪些Resource,该服务需要哪些HealthCheck等等。
3、Resource:定义一个资源,包括如何获取该资源,对该资源做Get/Post/Delete/Query时,对应的各种业务逻辑。
4、Representation:定义了一个服务返回值对象,当服务返回该对象时,会自动的把该对象按属性值生成一个Json格式的字符串返回给服务调用者。
5、HealthCheck:在DropWizard为每个服务提供的OM框架中用到,通过它可以随时检测当前服务是否可用。

二、配置环境

1. eclipse新建maven项目

2. 配置pom.xml,加入dropwizard需要的依赖

[code=plain]<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.wbf</groupId>
<artifactId>dropwizardTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>dropwizard test</name>

<properties>
<dropwizard.version>0.9.2</dropwizard.version>
</properties>

<dependencies>
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-core</artifactId>
<version>${dropwizard.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.helloworld.HelloWorldApplication</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>

</plugins>
</build>

</project>

3. 加入dropwizard的环境配置文件:hello-world.yml,将其放到项目的根目录下

[code=plain]template: Hello, %s!
defaultName: Stranger


三、示例代码

1. Configuration

[code=plain]package com.example.helloworld;

import org.hibernate.validator.constraints.NotEmpty;

import com.fasterxml.jackson.annotation.JsonProperty;

import io.dropwizard.Configuration;

public class HelloWorldConfiguration extends Configuration {
@NotEmpty
private String template;
@NotEmpty
private String defaultName = "Stranger";

@JsonProperty
public String getTemplate() {
return template;
}

@JsonProperty
public void setTemplate(String template) {
this.template = template;
}

@JsonProperty
public String getDefaultName() {
return defaultName;
}

@JsonProperty
public void setDefaultName(String defaultName) {
this.defaultName = defaultName;
}

}

2. Resource

[code=plain]package com.example.helloworld.resources;

import java.util.concurrent.atomic.AtomicLong;

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

import com.codahale.metrics.annotation.Timed;
import com.example.helloworld.core.Saying;
import com.google.common.base.Optional;

@Path("/hello-world")
@Produces(MediaType.APPLICATION_JSON)
public class HelloWorldResource {
private final String template;
private final String defaultName;
private final AtomicLong counter;

public HelloWorldResource(String template, String defaultName) {
this.template = template;
this.defaultName = defaultName;
this.counter = new AtomicLong();
}

@GET
@Timed
public Saying sayHello(@QueryParam("name") Optional<String> name) {
final String value = String.format(template, name.or(defaultName));
return new Saying(counter.incrementAndGet(), value);
}
}

3. HealthCheck

[code=plain]package com.example.helloworld.health;

import com.codahale.metrics.health.HealthCheck;

public class TemplateHealthCheck extends HealthCheck {
private final String template;

public TemplateHealthCheck(String template) {
this.template = template;
}

@Override
protected Result check() throws Exception {
final String saying = String.format(template, "TEST");
if (!saying.contains("TEST")) {
return Result.unhealthy("template doesn't include a name");
}
return Result.healthy();
}
}

4. Application

[code=plain]package com.example.helloworld;

import com.example.helloworld.health.TemplateHealthCheck;
import com.example.helloworld.resources.HelloWorldResource;

import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;

public class HelloWorldApplication extends Application<HelloWorldConfiguration>{

public static void main(String[] args) throws Exception {
new HelloWorldApplication().run("server", "hello-world.yml");
}

@Override
public void run(HelloWorldConfiguration configuration, Environment environment) throws Exception {
final HelloWorldResource resource = new HelloWorldResource(
configuration.getTemplate(),
configuration.getDefaultName()
);
environment.jersey().register(resource);

final TemplateHealthCheck healthCheck = new TemplateHealthCheck(configuration.getTemplate());
environment.healthChecks().register("template", healthCheck);
}

@Override
public String getName() {
return "hello-world";
}

@Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
super.initialize(bootstrap);
}

}

5. 返回的json格式的数据,例子

[code=plain]{
"id": 1,
"content": "Hi!"
}

6. 新建POJO类来封装返回数据

[code=plain]package com.example.helloworld.core;

import org.hibernate.validator.constraints.Length;

import com.fasterxml.jackson.annotation.JsonProperty;

public class Saying {
private long id;

@Length(max=3)
private String content;

public Saying() {}

public Saying(long id, String content) {
this.id = id;
this.content = content;
}

@JsonProperty
public long getId() {
return id;
}

@JsonProperty
public void setId(long id) {
this.id = id;
}

@JsonProperty
public String getContent() {
return content;
}

@JsonProperty
public void setContent(String content) {
this.content = content;
}

}

6. 回到eclipse中,在HelloWorldApplication直接Running As-->Java Application,启动服务

会输出如下信息:

[code=plain]INFO  [2016-05-03 07:57:14,290] org.eclipse.jetty.util.log: Logging initialized @1236ms
INFO  [2016-05-03 07:57:14,373] io.dropwizard.server.ServerFactory: Starting hello-world
INFO  [2016-05-03 07:57:14,380] io.dropwizard.server.DefaultServerFactory: Registering jersey handler with root path prefix: /
INFO  [2016-05-03 07:57:14,397] io.dropwizard.server.DefaultServerFactory: Registering admin handler with root path prefix: /
INFO  [2016-05-03 07:57:14,433] org.eclipse.jetty.setuid.SetUIDListener: Opened application@136fbc5{HTTP/1.1}{0.0.0.0:8080}
INFO  [2016-05-03 07:57:14,434] org.eclipse.jetty.setuid.SetUIDListener: Opened admin@cb4636{HTTP/1.1}{0.0.0.0:8081}
INFO  [2016-05-03 07:57:14,436] org.eclipse.jetty.server.Server: jetty-9.2.13.v20150730
INFO  [2016-05-03 07:57:14,952] io.dropwizard.jersey.DropwizardResourceConfig: The following paths were found for the configured resources:

GET     /hello-world (com.example.helloworld.resources.HelloWorldResource)

INFO  [2016-05-03 07:57:14,954] org.eclipse.jetty.server.handler.ContextHandler: Started i.d.j.MutableServletContextHandler@13cab44{/,null,AVAILABLE}
INFO  [2016-05-03 07:57:14,958] io.dropwizard.setup.AdminEnvironment: tasks =

POST    /tasks/log-level (io.dropwizard.servlets.tasks.LogConfigurationTask)
POST    /tasks/gc (io.dropwizard.servlets.tasks.GarbageCollectionTask)

INFO  [2016-05-03 07:57:14,962] org.eclipse.jetty.server.handler.ContextHandler: Started i.d.j.MutableServletContextHandler@7715db{/,null,AVAILABLE}
INFO  [2016-05-03 07:57:14,976] org.eclipse.jetty.server.ServerConnector: Started application@136fbc5{HTTP/1.1}{0.0.0.0:8080}
INFO  [2016-05-03 07:57:14,977] org.eclipse.jetty.server.ServerConnector: Started admin@cb4636{HTTP/1.1}{0.0.0.0:8081}
INFO  [2016-05-03 07:57:14,978] org.eclipse.jetty.server.Server: Started @1925ms

当看到INFO [2016-05-03 07:57:14,978] org.eclipse.jetty.server.Server: Started @1925ms时,表示服务启动成功。

7. 打开浏览器,在地址栏中输入(例子):http://localhost:8080/hello-world?name=zhangsan

可以得到如下信息:

[code=plain]{"id":1,"content":"Hello, zhangsan!"}

至此,通过dropwizard来快速部署RESTful Service服务完毕。

8. 执行逻辑分析

1). HelloWorldApplication --> main() --> initialize() --> getName()

先依次调用HelloWorldApplication的main()方法-->initialize()方法-->getName()方法

2). HelloWorldApplication --> run(HelloWorldConfiguration configuration, Environment environment)

因为HelloWorldApplication继承了Application<HelloWorldConfiguration>,所以在调用HelloWorldApplication的run()方法之前dropwizard会通过读取hello-world.yml文件来初始化run()方法的configuration参数。run()方法主要用来注册用户资源。

3). 执行HelloWorldApplication的run()方法,注册用户资源

比如当前的代码中,注册了用来整合返回值显示模板和默认访问用户的HelloWorldResource和用来检查自定义template是否符合标准的TemplateHealthCheck

4). 前三步执行完毕后,服务已经启动成功

5). 浏览器地址栏输入:http://localhost:8080/hello-world?name=zhangsan进行访问

因为HelloWorldResource添加了@Path("/hello-world")和@Produces(MediaType.APPLICATION_JSON)注解,它的sayHello()方法添加了@GET方法,并且sayHello()方法的参数Optional<String> name添加了@QueryParam("name")注解,所以dropwizard接收到该浏览器访问时,会将name=zhangsan的值赋给sayHello()方法的name参数,最后sayHello()方法根据所得的值,构建Saying类实例对象,返回给浏览器(以json格式)。

四、补充

通过maven将项目打包成jar包,达到可以在cmd中可以 java -jar xxx.jar来运行

1. 打开cmd,进入到maven项目的根目录,执行mvn package

2. 打包成功后,根目录下回多出一个target目录,进入其中找到项目的jar包,如我当前的jar包名字是:dropwizardTest-0.0.1-SNAPSHOT.jar

3. 将dropwizardTest-0.0.1-SNAPSHOT.jar拷贝到一个指定目录,如:test,同时需要将dropwizard环境配置文件也拷贝到test目录下(当前我的配置文件时hello-world.yml)

4. 启动cmd,进入到test目录下,执行如下命令java -jar dropwizardTest-0.0.1-SNAPSHOT.jar,如果成功,则输出信息也前面通过eclipse run启动时输出的信息基本一致。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Dropwizard RESTful