• Dropwizard框架入门


    最近项目用到了Dropwizard框架,个人感觉还不错,那么这里就从他们官网入手,然后加上自己的实现步骤让大家初步了解这个框架。

    官网对DW(Dropwizard)的定义是跨越了一个库和框架之间的界限。他的目标是提供一个生产就绪的web应用程序所需的一切性能可靠的实现。那么这句话可能有些绕,我个人理解就是他能免去我们部署web应用的很多步骤。由于这个功能被提取到可以重复使用的库中,我们的应用程序保持很大程度的精简和集中,这样可以减少我们程序的上线时间和维护负担。

    Jetty for HTTP

    由于Web应用不可能缺少HTTP,DW使用Jetty Http库将一个非常棒的HTTP服务器嵌入到我们的项目中。DW不是将你的程序提交到复杂的服务器上,DW上有个main方法来启动我们的服务器,DW是将我们的应用作为一个简单的线程来跑,消去了Java生产环境中一些非常复杂令人讨厌的过程,并且允许我们使用所有现有的Unix进程管理工具。

    Jersey for REST

    为了定义Restful的web应用,我们发现在性能和特性方面没有什么能比得过Jersey。它允许你编写干净的,可以测试的类,这个类可以优雅的将http请求映射成为简单的Java对象。它支持流输出,矩阵URL参数,条件GET请求,还有更多。

    Jackson for JSON

    在数据格式方面,JSON已经成为了网络的通用语,Jackson在jvm中就是Json的龙头老大。除了像闪电一样快速,他有一个复杂的对象映射,允许你直接导出你的域模型。

    Metrics for metrics

    Metrics库对事物进行舍入,在你的生产环境中,为你提供独一无二的洞察力。(也就是说这个是用来监控)那么到了这里,我们关于DW的总体印象应该已经差不多了,下面我结合官网实际操作。

    我使用maven和idea进行开发,项目名字为:dw_demo。关于如何创建maven项目不解释,创建完项目后如图所示:

    然后打开我们的pom.xml文件,加入dw的依赖(以下并非完全pom文件,仅展现部分):

    <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>

    Creating A Configuration Class

     
    每个DW应用都有他自己的子类:Configuration,这个类指定环境中特定的参数。这
    些参数在YAML类型的配置文件中被指定,其被反序列化为应用程序配置类的实例并验
    证。(这句话的意思就是这个配置文件中指定的参数,会被映射到我们项目的一个类)
    我们将要构建的是一个helloworld高性能服务。我们的一个要求就是我们需要能够在不同
    的环境中让它说hello。在开始之前我们需要指定至少两个内容:一个说hello的模板 还有
    一个默认的名字以防用户忘记指定。
     
    那么我下面开始创建我的配置文件:
     
     

    内容如下:

    package com.config;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    import io.dropwizard.Configuration;
    import org.hibernate.validator.constraints.NotEmpty;
    
    /**
     * Created by moon on 2017/1/13.
     */
    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 name) {
            this.defaultName = name;
        }
    }

    当这个类被从YAML配置文件反序列化的时候,他会从YAML对象中获取两个根层次的变量:template 用来说helloworld的模板。defaultName 默认的名字。template和defaultName都用@NotEmpty被注释,所以在YAML配置文件中如果有空值或者忘了其中一者,异常将会被抛出,我们的应用将不会被启动。

    defaultName和template的get 和set 方法都被@JsonProperty标注,这不止允许jackson从YAML配置文件反序列化,同样允许它序列化。

    然后我们创建一个YAML的配置文件:

    里面的内容如下:

    template: Hello, %s!
    defaultName: Stranger

    大家可以看到,与我们的配置类中的变量一一对应,相信很多人看到这里就明白了。

    Creating An Application Class

    结合我们项目中的Configuration子类,我们的Application的子类形成了我们DW的应用的核心。Application的子类把不同的提供各式各样功能的包和命令拉取到了一起。

    现在,我们开始建立我们的Application子类:

    其内容如下:

    package com.app;
    
    import com.config.HelloWorldConfiguration;
    import io.dropwizard.Application;
    import io.dropwizard.setup.Bootstrap;
    import io.dropwizard.setup.Environment;
    
    /**
     * Created by moon on 2017/1/13.
     */
    public class HelloWorldApplication extends Application<HelloWorldConfiguration> {
        public static void main(String[] args) throws Exception {
            new HelloWorldApplication().run(args);
        }
    
        @Override
        public String getName() {
            return "hello-world";
        }
    
        @Override
        public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
            // nothing to do yet
        }
    
        @Override
        public void run(HelloWorldConfiguration configuration,
                        Environment environment) {
            // nothing to do yet
        }
    
    }

    正如我们所看到的,HelloWorldApplication使用应用程序的configuration进行参数化。(因为用了我们的HelloWorldConfiuration,而它是Configuration的子类)。

    initialize方法用于配置应用在正式启动之前所需:包,配置源等。同时我们需要加入一个main方法,这是我们应用的入口。到目前为止,我们并没有实现任何的功能,所以我们的run方法有点无趣,让我们开始丰富它。

    Creating A Representation Class

    在我们开始继续我们的程序之前,我们需要停下来思考一下我们程序的API。幸运的是,我们的应用需要符合行业标准。RFC 1149(别问我这是什么,连这个都不知道,我tm也不知道)。他指定了helloworld saying的如下json表达形式:

    {
      "id": 1,
      "content": "Hi!"
    }

    id字段是语法的唯一标识符。content是说的具体内容。

    为了建模这个表示,我们需要创建一个表示类 :

    该类的内容如下:

    package com.api;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    import org.hibernate.validator.constraints.Length;
    
    /**
     * Created by moon on 2017/1/13.
     */
    public class Saying {
        private long id;
    
        @Length(max = 3)
        private String content;
    
        public Saying() {
            // Jackson deserialization
        }
    
        public Saying(long id, String content) {
            this.id = id;
            this.content = content;
        }
    
        @JsonProperty
        public long getId() {
            return id;
        }
    
        @JsonProperty
        public String getContent() {
            return content;
        }
    }

    这是一个非常简单的POJO,但是有些需要注意的地方。

    首先,他是不可更改的。这使得saying在多线程环境和单线程环境非常容易被推理。其次,它使用java的JavaBean来保存id和content属性。这允许jackson把他序列化为我们需要的JSON。jackson对象的映射代码将会使用getId()返回的对象来填充JSON对象的id字段,content同理。最后,bean利用验证来确保内容不大于3。

    Creating A Resource Class

    Jersey资源是DW应用程序的肉和土豆(这种比喻我也是醉了)。每个资源类都与URL相关联(这个很重要,后面有说)。对于我们的应用程序来说,我们需要一个resources来通过url:/helloworld来返回新的Saying实例对象。

    现在我们开始建立的Resource:

    类的内容如下:

    package com.resource;
    
    import com.api.Saying;
    import com.codahale.metrics.annotation.Timed;
    import com.google.common.base.Optional;
    
    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 java.util.concurrent.atomic.AtomicLong;
    
    /**
     * Created by moon on 2017/1/13.
     */
    @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);
        }
    
    }

    HelloWorldResource有两个声明:@Path和@Produces。@Path("/hello-world")告诉Jersey这个resource可以通过 "/hello-world"URL被访问。

    @Produces(MediaType.APPLICATION_JSON)让Jersey的内容协商代码知道这个资源产生的是application/json.

    HelloWorldResource构造器接收两个参数,创建saying的template和当用户没有指明名字时的默认名称。AtomicLong为我们提供一种线程安全,简易的方式去生成(ish)ID。

    sayHello方法是这个类的肉,也是一个非常简单的方法。@QueryParam("name")告诉Jersey把在查询参数中的name映射到方法中的name中。如果一个客户发送请求到:/hello-world?name=Dougie,sayHello 方法将会伴随Optional.of("Dougie")被调用。如果查询参数中没有name,sayHello将会伴随着Optional.absent()被调用。

    在sayHello方法里面,我们增加计数器的值,使用String.format来格式化模板,返回一个新的Saying实例。因为sayHello被@Timed注释,DW将会自动调用他的持续时间和速率记录为度量定时器。

    一旦sayHello返回,Jersey将会采用Saying的实例,并寻找一个提供程序类来将Saying实例写为:application/json。

    Registering A Resource

    在这些正式工作之前,我们需要到HelloWorldApplication中,并将新的resouce加入其中,在run方法中我们可以读取到HelloWorldConfiguration的template和defaultName实例,创建一个新的HelloWorldResource实例,并将其加入到新的Jersey环境中。

    我们HelloWorldApplication中新的run方法如下:

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

    当我们的应用启动的时候,我们使用配置文件中的参数创建一个新的资源类实例,并传递给environment.

    在pom文件中加入:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</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.app.HelloWorldApplication</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
    
        </plugins>
    </build>

    然后打包:

    打包成功后,在我们的target目录下面会出现我们所需的包:

    然后我们开始运行:

    这里面官方为我们提供两个参数,我们需要启动服务,所以后面加入server参数,重新启动如下:

    这说明我们的项目已经启动了,那么让我们访问一下url看是否正确:



    返回结果正常,没毛病。

    以上仅仅是DW的初步,还有许多其他功能,由于时间关系,不做详细介绍,如果

    有时间我会再奉上一版深度版的。链接为:

    DW官网深层次内容

    希望这次的讲解对大家有帮助,感谢开源。

  • 相关阅读:
    C语言时间函数
    sqlplus 配置方法及相关命令
    EDdb 是ED数据
    关于数据库性能管理专家的一个网站
    实用小技巧:在键盘没有小键盘时怎么打开任务管理器
    l来自wentao:项目加入缓存(redis),实时调试时用 -----可视化缓存,flushdb
    转:影响数据检索效率的几个因素
    apache-storm-1.0.3安装部署
    Hadoop2.7.3+spark2.1.0+hbase0.98分布式集群部署
    /etc/security/limits.conf的相关说明
  • 原文地址:https://www.cnblogs.com/pangguoming/p/6855180.html
Copyright © 2020-2023  润新知