从零学 Dropwizard:手把手搭轻量 Java 微服务,告别 Spring 臃肿

简介: Dropwizard 整合 Jetty、Jersey 等成熟组件,开箱即用,无需复杂配置。轻量高效,启动快,资源占用少,内置监控、健康检查与安全防护,搭配 Docker 部署便捷,是构建生产级 Java 微服务的极简利器。

如果你写 Java 微服务时,总被 Spring 的复杂配置、冗余依赖搞得头大,想找个 “轻量又能打” 的工具,那 Dropwizard 绝对适合你!

它不是全新框架,而是把 Java 生态里成熟的工具(Jetty、Jersey、Jackson、Metrics)打包整合,配好默认设置,拿来就能用 —— 不用写 XML、不用解决依赖冲突,几行代码就能搭出生产级微服务。

今天就从 0 开始,带你走完 “认知→搭建→开发→扩展→部署” 全流程,每个步骤都附代码和操作命令,新手也能跟着做,再也不用担心内容中断!

一、先搞懂:Dropwizard 到底好在哪?

在动手前,先明确它的核心优势,知道为啥比 Spring 轻量高效:

1. 开箱即用,不用折腾配置

Spring 得自己整合 Web 服务器、REST 框架、JSON 工具,而 Dropwizard 默认全带了:

  • Jetty 嵌入式服务器:不用装 Tomcat/JBoss,服务打成 “胖 JAR”,双击就能跑,省了运维成本;

  • Jersey REST 框架:用注解写接口(比如@GET@Path),不用手动配路由;

  • Jackson JSON 工具:Java 对象自动转 JSON,不用写转换器;

  • Logback+Metrics:日志分级、服务监控内置,不用额外集成。

只需要引一个dropwizard-core依赖,所有核心工具都能拉过来,新手 10 分钟就能上手。

2. 轻量高效,资源占用少

Spring 的 IOC 容器、AOP 特性虽灵活,但会占用额外内存、拖慢启动速度。Dropwizard 走 “极简路线”:

  • 核心 JAR 包仅几十 MB,比 Spring Boot 小一半;

  • 启动快,秒级就能完成(Spring Boot 常需几秒到十几秒);

  • 运行时接近原生 Java 性能,适合高频接口、实时数据场景。

3. 生产级特性全,不用自己开发

企业服务需要的健康检查、监控、安全防护,Dropwizard 都内置了:

  • 健康检查:默认查死锁、服务存活,支持自定义(比如查数据库连接、第三方 API 可用性);

  • 监控指标:访问/metrics就能看接口响应时间、请求量、JVM 内存;

  • 日志管理:支持按环境(开发 / 生产)配置日志级别,方便排查问题;

  • 可移植性:“胖 JAR” 格式,有 Java 环境就能跑,适配 Docker、K8s。

4. 代码少,开发效率高

不用写重复模板代码:

  • 项目结构标准化,不用手动建src/main/java等目录;

  • 接口开发仅需注解,不用注册 Controller、解析请求参数;

  • 配置用 YAML 文件,自动映射为 Java 变量,不用手动读配置。

二、环境准备:3 个工具必须装

动手前先搭好环境,就 3 个东西,几分钟就能搞定:

  1. JDK 11 及以上:Dropwizard 4.x 最低要求 JDK 11,若用旧版本(3.x)可适配 JDK 8;
  • 验证:终端输java -version,显示11.0.x及以上即可。
  1. Maven 3.6+:用于依赖管理和项目打包;
  • 验证:终端输mvn -v,显示3.6.x及以上即可。
  1. 代码编辑器:推荐 IDEA 社区版(免费),Eclipse 也可以;
  • 提前新建空文件夹(比如dropwizard-demo),后续项目放这里。

三、第一步:搭项目(两种方式任选)

推荐用 Maven 模板自动生成项目,不用手动建文件;想懂原理也可以手动搭,两种方式都讲清楚。

方式 1:Maven 模板自动生成(推荐)

打开终端,进入刚才新建的dropwizard-demo文件夹,执行以下命令:

mvn archetype:generate \\

  -Dfilter=io.dropwizard.archetypes:java-simple

执行后按提示输入 4 个信息(按自己需求填,示例如下):

  • groupId:项目组织 ID,比如com.example

  • artifactId:项目名,比如demo-service

  • version:版本号,默认1.0-SNAPSHOT

  • package:代码包名,比如com.example.demo

输完后按Y确认,Maven 会自动生成标准项目结构:

demo-service/

├── src/

│   ├── main/

│   │   ├── java/

│   │   │   └── com/

│   │   │       └── example/

│   │   │           └── demo/

│   │   │               ├── DemoApplication.java  # 服务入口

│   │   │               ├── DemoConfiguration.java # 配置类

│   │   │               └── DemoResource.java      # 接口类

│   │   └── resources/  # 放配置文件

│   └── test/  # 测试代码

└── pom.xml  # 依赖配置

方式 2:手动建 Maven 项目(学原理用)

  1. 打开 IDEA,新建 “Maven Project”,选 “Create from archetype”→“maven-archetype-quickstart”;

  2. 填坐标(groupId=com.exampleartifactId=demo-service),完成创建;

  3. 替换pom.xml内容(加 Dropwizard 依赖和打包插件):

<?xml version="1.0" encoding="UTF-8"?>

<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.example</groupId>

   <artifactId>demo-service</artifactId>

   <version>1.0-SNAPSHOT</version>

   <properties>

       <maven.compiler.source>11</maven.compiler.source>

       <maven.compiler.target>11</maven.compiler.target>

       <dropwizard.version>4.0.2</dropwizard.version>

   </properties>

   <dependencies>

       <!-- Dropwizard核心依赖 -->

       <dependency>

           <groupId>io.dropwizard</groupId>

           <artifactId>dropwizard-core</artifactId>

           <version>\${dropwizard.version}</version>

       </dependency>

   </dependencies>

   <build>

       <plugins>

           <!-- 打包成胖JAR -->

           <plugin>

               <groupId>org.apache.maven.plugins</groupId>

               <artifactId>maven-shade-plugin</artifactId>

               <version>3.5.1</version>

               <executions>

                   <execution>

                       <phase>package</phase>

                       <goals>

                           <goal>shade</goal>

                       </goals>

                       <configuration>

                           <transformers>

                               <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

                                   <mainClass>com.example.demo.DemoApplication</mainClass>

                               </transformer>

                           </transformers>

                       </configuration>

                   </execution>

               </executions>

           </plugin>

       </plugins>

   </build>

</project>
  1. src/main/java/com/example/demo下手动建 3 个类:DemoApplicationDemoConfigurationDemoResource

四、第二步:写核心代码,跑通第一个接口

Dropwizard 项目核心就 3 个类,代码都很短,咱们一个个写完整。

1. 配置类:DemoConfiguration.java

负责把 YAML 配置转成 Java 变量,即使暂时不用自定义配置,也得继承Configuration

package com.example.demo;

import io.dropwizard.Configuration;

import com.fasterxml.jackson.annotation.JsonProperty;

import org.hibernate.validator.constraints.NotEmpty;

public class DemoConfiguration extends Configuration {

   // 示例:自定义“欢迎语”配置,YAML里的key对应这里的变量

   @NotEmpty  // 校验配置必填,空值会启动报错

   private String welcomeMsg = "Hello, Dropwizard!";

   // Getter和Setter:Dropwizard通过这些读取配置

   @JsonProperty

   public String getWelcomeMsg() {

       return welcomeMsg;

   }

   @JsonProperty

   public void setWelcomeMsg(String welcomeMsg) {

       this.welcomeMsg = welcomeMsg;

   }

}

2. 入口类:DemoApplication.java

服务的 “开关”,负责启动服务、注册接口和组件:

package com.example.demo;

import io.dropwizard.Application;

import io.dropwizard.setup.Bootstrap;

import io.dropwizard.setup.Environment;

public class DemoApplication extends Application<DemoConfiguration> {

   // 服务入口:main方法,启动就靠它

   public static void main(String\[] args) throws Exception {

       new DemoApplication().run(args);

   }

   // 初始化:注册插件(如模板引擎),暂时不用就空着

   @Override

   public void initialize(Bootstrap<DemoConfiguration> bootstrap) {

       // 示例:若需集成Freemarker模板,加这行:

       // bootstrap.addBundle(new FreemarkerBundle());

   }

   // 核心逻辑:注册接口、健康检查等

   @Override

   public void run(DemoConfiguration config, Environment env) {

       // 注册接口类,把配置里的欢迎语传进去

       env.jersey().register(new DemoResource(config.getWelcomeMsg()));

   }

}

3. 接口类:DemoResource.java

用 Jersey 注解写 REST 接口,Dropwizard 自动处理路由和 JSON 转换:

package com.example.demo;

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.Collections;

import java.util.Map;

@Path("/hello")  // 接口根路径:http://localhost:8080/hello

@Produces(MediaType.APPLICATION\_JSON)  // 响应格式:JSON

public class DemoResource {

   private final String welcomeMsg;

   // 构造函数:接收配置里的欢迎语

   public DemoResource(String welcomeMsg) {

       this.welcomeMsg = welcomeMsg;

   }

   // 1. 基础接口:无参数,返回欢迎语

   @GET

   public Map<String, String> sayHello() {

       // Jackson自动把Map转成JSON

       return Collections.singletonMap("message", welcomeMsg);

   }

   // 2. 带参数接口:接收name参数,如http://localhost:8080/hello/name?name=张三

   @GET

   @Path("/name")  // 子路径,拼接后为/hello/name

   public Map<String, String> sayHelloWithName(@QueryParam("name") String name) {

       // 替换欢迎语里的内容

       String msg = welcomeMsg.replace("Dropwizard", name);

       return Collections.singletonMap("message", msg);

   }

}

4. 写配置文件:config.yml

src/main/resources下新建config.yml,配置端口、日志和自定义参数:

# 服务端口配置:8080=API端口(对外),8081=管理端口(监控/健康检查)

server:

 applicationConnectors:

   \- type: http

     port: 8080

 adminConnectors:

   \- type: http

     port: 8081

# 日志配置:开发用INFO(详细),生产用WARN(仅警告/错误)

logging:

 level: INFO

# 自定义配置:对应DemoConfiguration里的welcomeMsg

welcomeMsg: "Hello, Dropwizard!"

5. 启动并测试服务

步骤 1:打包项目

终端进入demo-service目录,执行打包命令:

mvn clean package

打包成功后,target目录会生成demo-service-1.0-SNAPSHOT.jar(胖 JAR)。

步骤 2:启动服务

执行启动命令(注意替换 JAR 包名):

java -jar target/demo-service-1.0-SNAPSHOT.jar server src/main/resources/config.yml

启动成功会看到Started日志,说明服务已跑起来:

INFO  \[2025-05-20 16:00:00,000] org.eclipse.jetty.server.Server: Started @1200ms

INFO  \[2025-05-20 16:00:00,001] io.dropwizard.server.DefaultServerFactory: Started application connector on 0.0.0.0:8080

步骤 3:测试接口

用 curl 或浏览器访问,验证接口可用:

# 测试基础接口

curl http://localhost:8080/hello

# 响应:{"message":"Hello, Dropwizard!"}

# 测试带参数接口

curl http://localhost:8080/hello/name?name=张三

# 响应:{"message":"Hello, 张三!"}

# 测试健康检查(管理端口)

curl http://localhost:8081/healthcheck

# 响应:{"deadlocks":{"healthy":true}}

五、第三步:加数据库,实现增删改查

实际项目需要操作数据库,Dropwizard 用 JDBI3(轻量 ORM)很方便,不用写 XML。

1. 加依赖

pom.xmldependencies里加 JDBI3 和 MySQL 驱动:

<!-- JDBI3:操作数据库 -->

<dependency>

   <groupId>io.dropwizard</groupId>

   <artifactId>dropwizard-jdbi3</artifactId>

   <version>\${dropwizard.version}</version>

</dependency>

<!-- MySQL驱动:连接MySQL数据库 -->

<dependency>

   <groupId>com.mysql</groupId>

   <artifactId>mysql-connector-j</artifactId>

   <version>8.4.0</version>

</dependency>

2. 配置数据库连接

修改src/main/resources/config.yml,加数据库配置(先手动建数据库demo_db):

# 原来的server、logging、welcomeMsg配置...

# 数据库配置

database:

 driverClass: com.mysql.cj.jdbc.Driver  # MySQL驱动类

 url: jdbc:mysql://localhost:3306/demo\_db?useSSL=false\&serverTimezone=UTC  # 数据库地址

 user: root  # 数据库用户名(按自己的改)

 password: 123456  # 数据库密码(按自己的改)

 maxWaitForConnection: 10s  # 最大连接等待时间

 minSize: 5  # 连接池最小连接数

 maxSize: 20  # 连接池最大连接数

3. 映射数据库配置

修改DemoConfiguration.java,加数据库配置的映射:

package com.example.demo;

import io.dropwizard.Configuration;

import io.dropwizard.db.DataSourceFactory;

import com.fasterxml.jackson.annotation.JsonProperty;

import org.hibernate.validator.constraints.NotEmpty;

public class DemoConfiguration extends Configuration {

   // 原来的welcomeMsg配置...

   @NotEmpty

   private String welcomeMsg = "Hello, Dropwizard!";

   // 新增:数据库配置,对应YAML里的database

   @JsonProperty("database")

   private DataSourceFactory database = new DataSourceFactory();

   // 新增:数据库配置的Getter

   public DataSourceFactory getDatabase() {

       return database;

   }

   // 原来的welcomeMsg Getter/Setter...

   @JsonProperty

   public String getWelcomeMsg() {

       return welcomeMsg;

   }

   @JsonProperty

   public void setWelcomeMsg(String welcomeMsg) {

       this.welcomeMsg = welcomeMsg;

   }

}

4. 写数据访问接口(DAO)

新建com.example.demo.dao包,写UserDAO.java(用注解写 SQL):

package com.example.demo.dao;

import org.jdbi.v3.sqlobject.customizer.Bind;

import org.jdbi.v3.sqlobject.statement.SqlQuery;

import org.jdbi.v3.sqlobject.statement.SqlUpdate;

public interface UserDAO {

   // 1. 建表:启动时自动创建users表(id自增主键,name用户名,age年龄)

   @SqlUpdate("CREATE TABLE IF NOT EXISTS users (" +

              "id INT AUTO\_INCREMENT PRIMARY KEY, " +

              "name VARCHAR(50) NOT NULL, " +

              "age INT NOT NULL)")

   void createTable();

   // 2. 新增用户:接收name和age参数

   @SqlUpdate("INSERT INTO users (name, age) VALUES (:name, :age)")

   void addUser(@Bind("name") String name, @Bind("age") int age);

   // 3. 查询用户:根据id查姓名

   @SqlQuery("SELECT name FROM users WHERE id = :id")

   String getUserNameById(@Bind("id") int id);

   // 4. 更新用户年龄:根据id改age

   @SqlUpdate("UPDATE users SET age = :age WHERE id = :id")

   void updateUserAge(@Bind("id") int id, @Bind("age") int age);

   // 5. 删除用户:根据id删记录

   @SqlUpdate("DELETE FROM users WHERE id = :id")

   void deleteUser(@Bind("id") int id);

}

5. 写用户接口(UserResource)

新建com.example.demo.resource包,写UserResource.java(处理用户增删改查请求):

package com.example.demo.resource;

import com.example.demo.dao.UserDAO;

import javax.ws.rs.\*;

import javax.ws.rs.core.MediaType;

import java.util.Collections;

import java.util.Map;

@Path("/users")  // 接口根路径:http://localhost:8080/users

@Produces(MediaType.APPLICATION\_JSON)  // 响应JSON

@Consumes(MediaType.APPLICATION\_JSON)  // 接收JSON请求体

public class UserResource {

   private final UserDAO userDAO;

   // 构造函数:注入UserDAO

   public UserResource(UserDAO userDAO) {

       this.userDAO = userDAO;

       this.userDAO.createTable();  // 启动时自动建表

   }

   // 1. 新增用户:POST请求,传{"name":"张三","age":20}

   @POST

   public Map<String, String> addUser(User user) {

       userDAO.addUser(user.getName(), user.getAge());

       return Collections.singletonMap("status", "success");

   }

   // 2. 查询用户:GET请求,路径带id,如http://localhost:8080/users/1

   @GET

   @Path("/{id}")

   public Map<String, String> getUser(@PathParam("id") int id) {

       String name = userDAO.getUserNameById(id);

       if (name == null) {

           return Collections.singletonMap("status", "用户不存在");

       }

       return Collections.singletonMap("name", name);

   }

   // 3. 更新年龄:PUT请求,如http://localhost:8080/users/1/age?age=25

   @PUT

   @Path("/{id}/age")

   public Map<String, String> updateAge(@PathParam("id") int id, @QueryParam("age") int age) {

       userDAO.updateUserAge(id, age);

       return Collections.singletonMap("status", "年龄更新成功");

   }

   // 4. 删除用户:DELETE请求,如http://localhost:8080/users/1

   @DELETE

   @Path("/{id}")

   public Map<String, String> deleteUser(@PathParam("id") int id) {

       userDAO.deleteUser(id);

       return Collections.singletonMap("status", "用户删除成功");

   }

}

// 内部类:接收新增用户的请求体

class User {

   private String name;

   private int age;

   // Getter和Setter:Jackson需通过这些解析JSON

   public String getName() {

       return name;

   }

   public void setName(String name) {

       this.name = name;

   }

   public int getAge() {

       return age;

   }

   public void setAge(int age) {

       this.age = age;

   }

}

6. 注册数据库组件

修改DemoApplication.javarun方法,注册 JDBI 和用户接口:

package com.example.demo;

import com.example.demo.dao.UserDAO;

import com.example.demo.resource.UserResource;

import io.dropwizard.Application;

import io.dropwizard.setup.Bootstrap;

import io.dropwizard.setup.Environment;

import io.dropwizard.db.DataSourceFactory;

import io.dropwizard.jdbi3.JdbiFactory;

import org.jdbi.v3.core.Jdbi;

import org.jdbi.v3.sqlobject.SqlObjectPlugin;

public class DemoApplication extends Application<DemoConfiguration> {

   public static void main(String\[] args) throws Exception {

       new DemoApplication().run(args);

   }

   @Override

   public void initialize(Bootstrap<DemoConfiguration> bootstrap) {}

   @Override

   public void run(DemoConfiguration config, Environment env) {

       // 1. 注册Hello接口(原代码保留)

       env.jersey().register(new DemoResource(config.getWelcomeMsg()));

       // 2. 新增:创建JDBI实例

       final JdbiFactory factory = new JdbiFactory();

       final Jdbi jdbi = factory.build(env, config.getDatabase(), "mysql");



       // 3. 启用SQL Object插件(支持DAO注解)

       jdbi.installPlugin(new SqlObjectPlugin());



       // 4. 获取UserDAO实例

       final UserDAO userDAO = jdbi.onDemand(UserDAO.class);



       // 5. 注册用户接口

       env.jersey().register(new UserResource(userDAO));



       // 6. 注册数据库健康检查(自动检查数据库连接)

       env.healthChecks().register("database", new DataSourceHealthCheck(config.getDatabase()));

   }

}

7. 测试数据库接口

启动服务后,用 curl 测试增删改查:

# 1. 新增用户:传JSON请求体

curl -X POST -H "Content-Type: application/json" -d '{"name":"张三","age":20}' http://localhost:8080/users

# 响应:{"status":"success"}

# 2. 查询用户:查id=1的用户

curl http://localhost:8080/users/1

# 响应:{"name":"张三"}

# 3. 更新年龄:把id=1的年龄改成22

curl -X PUT http://localhost:8080/users/1/age?age=22

# 响应:{"status":"年龄更新成功"}

# 4. 删除用户:删除id=1的用户

curl -X DELETE http://localhost:8080/users/1

# 响应:{"status":"用户删除成功"}

六、第四步:加监控,看接口响应时间和请求量

Dropwizard 内置 Metrics 监控,不用自己搭监控系统,还能对接 Prometheus 做可视化。

1. 查看默认监控数据

启动服务后,访问http://localhost:8081/metrics,能看到 JSON 格式的监控数据,关键指标:

  • jvm.memory.used:JVM 已用内存;

  • jetty.server.requests:接口总请求数、平均响应时间;

  • metrics.timer.jersey.resource.DemoResource.sayHello/hello接口的响应时间分布。

2. 自定义接口监控

给接口加@Timed(统计响应时间)或@Metered(统计调用频率)注解:

// 在DemoResource.java中添加注解

@Path("/hello")

public class DemoResource {

   // 新增:统计/hello接口响应时间

   @Timed(name = "hello.request.timer", description = "/hello接口响应时间")

   @GET

   public Map<String, String> sayHello() {

       return Collections.singletonMap("message", welcomeMsg);

   }

   // 新增:统计/hello/name接口调用频率(每秒多少次)

   @Metered(name = "hello.name.request.meter", description = "/hello/name接口调用频率")

   @GET

   @Path("/name")

   public Map<String, String> sayHelloWithName(@QueryParam("name") String name) {

       String msg = welcomeMsg.replace("Dropwizard", name);

       return Collections.singletonMap("message", msg);

   }

}

重启服务后,访问/metrics就能看到自定义监控指标。

3. 对接 Prometheus(可视化监控)

步骤 1:加依赖

pom.xml中添加 Prometheus 依赖:

<dependency>

   <groupId>io.dropwizard.metrics</groupId>

   <artifactId>metrics-prometheus</artifactId>

   <version>4.2.19</version>

</dependency>

步骤 2:注册 Prometheus 导出器

修改DemoApplication.javarun方法,添加监控暴露接口:

import io.dropwizard.metrics.MetricRegistry;

import io.prometheus.client.exporter.MetricsServlet;

@Override

public void run(DemoConfiguration config, Environment env) {

   // 原有代码...(注册接口、JDBI等)

   // 新增:获取MetricRegistry(Dropwizard的监控容器)

   MetricRegistry registry = env.metrics();



   // 注册Prometheus Servlet,通过/metrics/prometheus暴露数据

   env.servlets().addServlet("prometheus-metrics", new MetricsServlet(registry))

      .addMapping("/metrics/prometheus");

}

步骤 3:配置 Prometheus

  1. 下载 Prometheus(官网地址);

  2. 编辑prometheus.yml,添加抓取规则:

scrape\_configs:

 \- job\_name: "dropwizard-demo"

   static\_configs:

     \- targets: \["localhost:8081"]  # Dropwizard管理端口

   metrics\_path: "/metrics/prometheus"  # 监控数据接口

步骤 4:启动并查看

  1. 启动 Prometheus:双击prometheus.exe(Windows)或./prometheus(Linux);

  2. 访问http://localhost:9090,在 Graph 页面输入指标(如hello_request_timer_seconds_count),就能看到接口调用次数的图表;

  3. 若需更美观的仪表盘,可集成 Grafana,导入 JVM、HTTP 相关模板(如模板 ID:8563)。

七、第五步:加安全防护,避免接口裸奔

生产环境需做 HTTPS(加密传输)和密码认证(防止非法访问),Dropwizard 支持开箱即用。

1. 配置 HTTPS(加密传输)

步骤 1:生成证书

用 JDK 自带的keytool命令生成证书文件(keystore.jks),终端执行:

keytool -genkey -alias demo-service -keyalg RSA -keystore keystore.jks -keysize 2048

按提示输入:

  • 密钥库密码(如123456);

  • 姓名、单位等信息(随便填);

  • 最后输入yes确认,生成keystore.jks(放项目根目录)。

步骤 2:修改 YAML 配置

把 HTTP 端口换成 HTTPS,添加证书配置:

server:

 applicationConnectors:

   # 注释原有HTTP配置,新增HTTPS

   # - type: http

   #   port: 8080

   \- type: https

     port: 8443  # HTTPS端口(对外API)

     keyStorePath: keystore.jks  # 证书路径

     keyStorePassword: 123456  # 证书密码

     validateCerts: false  # 开发环境关闭证书校验(生产设为true)

 adminConnectors:

   # 管理端口也换成HTTPS

   \- type: https

     port: 8444  # HTTPS管理端口

     keyStorePath: keystore.jks

     keyStorePassword: 123456

# 原有其他配置(logging、database等)...

步骤 3:测试 HTTPS

启动服务后,用 curl 访问(加-k跳过证书校验):

curl -k https://localhost:8443/hello

# 响应:{"message":"Hello, Dropwizard!"}

2. 配置 Basic Auth(密码认证)

步骤 1:加依赖

pom.xml中添加认证依赖:

<dependency>

   <groupId>io.dropwizard</groupId>

   <artifactId>dropwizard-auth</artifactId>

   <version>\${dropwizard.version}</version>

</dependency>

步骤 2:写认证相关类

新建com.example.demo.auth包,写用户类和认证器:

package com.example.demo.auth;

import io.dropwizard.auth.AuthenticationException;

import io.dropwizard.auth.Authenticator;

import io.dropwizard.auth.basic.BasicCredentials;

import java.security.Principal;

import java.util.HashMap;

import java.util.Map;

import java.util.Optional;

// 1. 用户类:存储登录用户信息

public class UserPrincipal implements Principal {

   private final String username;

   public UserPrincipal(String username) {

       this.username = username;

   }

   @Override

   public String getName() {

       return username;

   }

}

// 2. 认证器:校验用户名密码

public class DemoAuthenticator implements Authenticator<BasicCredentials, UserPrincipal> {

   // 模拟用户库(生产环境需从数据库读取)

   private final Map<String, String> userMap = new HashMap<>();

   public DemoAuthenticator() {

       userMap.put("admin", "admin123");  // 用户名admin,密码admin123

       userMap.put("test", "test123");    // 用户名test,密码test123

   }

   @Override

   public Optional<UserPrincipal> authenticate(BasicCredentials credentials) throws AuthenticationException {

       // 校验用户名密码是否匹配

       if (userMap.containsKey(credentials.getUsername()) &&

           userMap.get(credentials.getUsername()).equals(credentials.getPassword())) {

           return Optional.of(new UserPrincipal(credentials.getUsername()));

       }

       return Optional.empty();  // 不匹配返回空

   }

}

步骤 3:注册认证器并保护接口

修改DemoApplication.javarun方法,注册认证组件:

import com.example.demo.auth.DemoAuthenticator;

import com.example.demo.auth.UserPrincipal;

import io.dropwizard.auth.AuthDynamicFeature;

import io.dropwizard.auth.AuthValueFactoryProvider;

import io.dropwizard.auth.basic.BasicCredentialAuthFilter;

@Override

public void run(DemoConfiguration config, Environment env) {

   // 原有代码...(注册JDBI、监控等)

   // 新增:1. 注册Basic Auth认证器

   env.jersey().register(new AuthDynamicFeature(

       new BasicCredentialAuthFilter.Builder<UserPrincipal>()

           .setAuthenticator(new DemoAuthenticator())  // 自定义认证器

           .setRealm("Demo Service")  // 认证域(弹窗提示用)

           .buildAuthFilter()

   ));

   // 2. 注册UserPrincipal,让@Auth注解能注入用户

   env.jersey().register(new AuthValueFactoryProvider.Binder<>(UserPrincipal.class));

   // 3. 注册受保护的接口(示例)

   env.jersey().register(new ProtectedResource());

}

// 新增:受保护的接口(需登录才能访问)

@Path("/protected")

@Produces(MediaType.APPLICATION\_JSON)

class ProtectedResource {

   // @Auth注解:自动注入当前登录用户

   @GET

   public Map<String, String> getProtectedData(@Auth UserPrincipal user) {

       return Collections.singletonMap("message", "欢迎登录," + user.getName() + "!这是私密数据");

   }

}

步骤 4:测试认证

# 错误密码(admin/123456)

curl -k -u admin:123456 https://localhost:8443/protected

# 响应:401 Unauthorized(未授权,提示输入正确密码)

浏览器访问https://localhost:8443/protected时,会弹出密码输入框,输入正确的admin/admin123才能看到内容,输错则提示 “无权访问”,确保接口安全。

八、第六步:部署服务,上生产环境

Dropwizard 服务是 “胖 JAR” 格式,推荐用 Docker 打包部署,适配 Linux、Windows 等不同环境,也方便后续在 K8s 集群中管理。

1. 编写 Dockerfile

在项目根目录新建Dockerfile,内容如下(基于轻量 JRE 镜像,减少镜像体积):

# 基础镜像:使用JRE 11(无需完整JDK,节省空间)

FROM openjdk:11-jre-slim

# 设置工作目录:把所有文件放在/app目录下,方便管理

WORKDIR /app

# 复制文件到容器:

# 1. 打包好的胖JAR(替换为实际JAR包名)

# 2. 配置文件(config.yml)

# 3. HTTPS证书(keystore.jks,若未启用HTTPS可删除)

COPY target/demo-service-1.0-SNAPSHOT.jar app.jar

COPY src/main/resources/config.yml config.yml

COPY keystore.jks keystore.jks

# 暴露端口:对应config.yml中的HTTPS端口(8443=API端口,8444=管理端口)

EXPOSE 8443 8444

# 启动命令:与本地启动命令一致,指定JAR包和配置文件

# 可添加JVM参数限制内存(如-Xms512m -Xmx1g,防止内存溢出)

ENTRYPOINT \["java", "-Xms512m", "-Xmx1g", "-jar", "app.jar", "server", "config.yml"]

2. 构建 Docker 镜像

步骤 1:提前打包项目

确保已通过 Maven 打包生成胖 JAR,若未打包需先执行:

mvn clean package

打包成功后,target目录会生成demo-service-1.0-SNAPSHOT.jar

步骤 2:构建镜像

在项目根目录执行 Docker 构建命令(-t指定镜像名和版本,最后.表示当前目录):

docker build -t demo-service:1.0 .

构建完成后,执行docker images可查看镜像:

docker images

# 输出示例:

# REPOSITORY    TAG       IMAGE ID       CREATED         SIZE

# demo-service  1.0       abc123456789   2 minutes ago   320MB

3. 运行 Docker 容器

步骤 1:启动容器

执行docker run命令,映射容器端口到宿主机(-p 宿主机端口:容器端口),后台运行(-d):

docker run -d \\

 -p 8443:8443 \\

 -p 8444:8444 \\

 \--name demo-service-container \\

 demo-service:1.0
  • -d:后台运行容器,避免终端关闭后服务停止;

  • --name:给容器起别名,方便后续管理(如停止、重启);

  • 端口映射:宿主机的 8443 端口对应容器的 8443 端口(API 访问),8444 对应 8444(管理端口)。

步骤 2:验证容器运行状态

执行docker ps查看运行中的容器:

docker ps

# 输出示例(包含容器ID、名称、端口映射等):

# CONTAINER ID   NAMES                     STATUS         PORTS

# def567890123   demo-service-container    Up 30 seconds  0.0.0.0:8443->8443/tcp, 0.0.0.0:8444->8444/tcp

若状态为Up,说明容器启动成功,此时可通过宿主机 IP 访问服务(如https://宿主机IP:8443/hello)。

步骤 3:容器管理常用命令

  • 停止容器:docker stop demo-service-container

  • 重启容器:docker restart demo-service-container

  • 查看容器日志(排查问题):docker logs -f demo-service-container-f实时刷新日志);

  • 删除容器(需先停止):docker rm demo-service-container

九、第七步:生产级最佳实践,避免踩坑

部署到生产环境后,需注意以下细节,确保服务稳定运行、便于维护:

1. 配置文件按环境分离,避免硬编码

开发、测试、生产环境的配置(如数据库地址、端口、日志级别)不同,建议创建多个配置文件:

  • config-dev.yml:开发环境(本地数据库、HTTP 端口、详细日志);

  • config-test.yml:测试环境(测试服务器数据库、HTTPS 端口、简化日志);

  • config-prod.yml:生产环境(生产数据库、正式 HTTPS 证书、仅警告日志)。

启动时指定对应配置文件即可,示例:

# 生产环境启动(本地启动)

java -jar app.jar server config-prod.yml

# Docker启动生产环境(修改Dockerfile的ENTRYPOINT,或启动时指定)

docker run -d -p 8443:8443 -p 8444:8444 --name demo-service-prod demo-service:1.0 java -jar app.jar server config-prod.yml

2. 日志持久化,方便问题排查

生产环境日志不能仅输出到控制台,需配置日志文件存储,并按时间 / 大小切割,避免日志文件过大。修改config-prod.yml的日志配置:

logging:

 level: WARN  # 生产环境仅输出警告和错误日志

 appenders:

   \- type: file  # 输出到文件

     currentLogFilename: /var/log/demo-service/service.log  # 当前日志文件路径

     archivedLogFilenamePattern: /var/log/demo-service/service-%d{yyyy-MM-dd}.log.gz  # 按日期归档(压缩)

     archivedFileCount: 30  # 保留30天的归档日志

     maxFileSize: 100MB  # 单个日志文件最大100MB,满后自动归档

Docker 部署时,需通过-v挂载宿主机目录到容器,确保日志持久化(容器删除后日志不丢失):

docker run -d \\

 -p 8443:8443 -p 8444:8444 \\

 -v /宿主机日志目录:/var/log/demo-service \  # 挂载日志目录

 \--name demo-service-container \\

 demo-service:1.0

3. 限制 JVM 资源,防止内存溢出

启动服务时指定 JVM 参数,限制最小 / 最大内存,避免服务占用过多宿主机资源导致崩溃。修改 Dockerfile 的ENTRYPOINT或启动命令:

# 示例:初始内存512MB,最大内存1GB

java -Xms512m -Xmx1g -jar app.jar server config.yml

根据服务器配置调整参数(如 4GB 内存的服务器,可设-Xms1g -Xmx2g)。

4. 编写自动化测试,保障功能稳定

dropwizard-testing模块写集成测试,自动启动服务并验证接口,避免手动测试遗漏问题。

步骤 1:添加测试依赖

pom.xml中添加:

<dependency>

   <groupId>io.dropwizard</groupId>

   <artifactId>dropwizard-testing</artifactId>

   <version>\${dropwizard.version}</version>

   <scope>test</scope>  <!-- 仅测试时生效 -->

</dependency>

步骤 2:编写测试类

src/test/java/com/example/demo下新建DemoResourceTest.java

package com.example.demo;

import io.dropwizard.testing.ResourceHelpers;

import io.dropwizard.testing.junit.DropwizardAppRule;

import org.junit.ClassRule;

import org.junit.Test;

import javax.ws.rs.client.Client;

import javax.ws.rs.client.ClientBuilder;

import javax.ws.rs.core.Response;

import static org.junit.Assert.assertEquals;

public class DemoResourceTest {

   // 启动测试服务:指定应用类和开发环境配置文件

   @ClassRule

   public static final DropwizardAppRule<DemoConfiguration> RULE =

       new DropwizardAppRule<>(DemoApplication.class, ResourceHelpers.resourceFilePath("config-dev.yml"));

   // 测试/hello接口

   @Test

   public void testSayHello() {

       // 创建HTTP客户端,发送请求到测试服务

       Client client = ClientBuilder.newClient();

       Response response = client.target(

               "http://localhost:" + RULE.getLocalPort() + "/hello"  // RULE.getLocalPort()获取测试服务端口

           ).request().get();

       // 断言:状态码为200(成功),返回内容正确

       assertEquals(200, response.getStatus());

       assertEquals("{\\"message\\":\\"Hello, Dropwizard!\\"}", response.readEntity(String.class));

   }

   // 测试/hello/name接口(带参数)

   @Test

   public void testSayHelloWithName() {

       Client client = ClientBuilder.newClient();

       Response response = client.target(

               "http://localhost:" + RULE.getLocalPort() + "/hello/name?name=测试用户"

           ).request().get();

       assertEquals(200, response.getStatus());

       assertEquals("{\\"message\\":\\"Hello, 测试用户!\\"}", response.readEntity(String.class));

   }

}

步骤 3:运行测试

在 IDEA 中右键运行测试类,或通过 Maven 命令执行:

mvn test

测试通过会显示BUILD SUCCESS,确保接口功能正常。

5. 避免过度扩展,贴合 Dropwizard 轻量定位

Dropwizard 的设计初衷是 “轻量高效”,适合开发纯 REST API 服务(如数据接口、小程序后端)。若需复杂的 IOC 容器、AOP 切面、分布式事务等功能,建议切换到 Spring Boot;若仅需稳定的接口服务,Dropwizard 是更优选择,避免为 “用不上的功能” 付出性能代价。

九、总结

Dropwizard 的核心价值在于 “整合成熟工具,简化开发流程”—— 它不创造新功能,而是把 Jetty、Jersey、Jackson 等经过验证的组件打包成 “即用套件”,让开发者摆脱依赖冲突和配置繁琐的困扰。

从 “Hello World” 接口到集成数据库、监控、安全防护的生产级服务,再到用 Docker 部署上线,整个流程都围绕 “轻量、高效” 展开,尤其适合厌烦 Spring 臃肿配置、追求开发效率的团队。

如果你需要快速交付稳定的 Java 微服务,且核心需求是 REST API 开发,Dropwizard 绝对值得尝试 —— 跟着本文的步骤,从基础接口到生产部署,你能以最少的代码、最低的学习成本,搭建起满足企业需求的微服务系统。

目录
相关文章
|
1月前
|
负载均衡 Java API
《深入理解Spring》Spring Cloud 构建分布式系统的微服务全家桶
Spring Cloud为微服务架构提供一站式解决方案,涵盖服务注册、配置管理、负载均衡、熔断限流等核心功能,助力开发者构建高可用、易扩展的分布式系统,并持续向云原生演进。
|
1月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
1月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
115 8
|
2月前
|
人工智能 Java API
构建基于Java的AI智能体:使用LangChain4j与Spring AI实现RAG应用
当大模型需要处理私有、实时的数据时,检索增强生成(RAG)技术成为了核心解决方案。本文深入探讨如何在Java生态中构建具备RAG能力的AI智能体。我们将介绍新兴的Spring AI项目与成熟的LangChain4j框架,详细演示如何从零开始构建一个能够查询私有知识库的智能问答系统。内容涵盖文档加载与分块、向量数据库集成、语义检索以及与大模型的最终合成,并提供完整的代码实现,为Java开发者开启构建复杂AI智能体的大门。
1254 58
|
2月前
|
监控 Kubernetes Java
使用 New Relic APM 和 Kubernetes Metrics 监控 EKS 上的 Java 微服务
在阿里云AKS上运行Java微服务常遇性能瓶颈与OOMKilled等问题。本文教你通过New Relic实现集群与JVM双层监控,集成Helm部署、JVM代理注入、GC调优及告警仪表盘,打通从节点资源到应用内存的全链路观测,提升排障效率,保障服务稳定。
183 1
|
3月前
|
前端开发 Java 开发者
Java新手指南:在Spring MVC中使用查询字符串与参数
通过结合实际的需求和业务逻辑,开发者可以灵活地利用这些机制,为用户提供更丰富而高效的Web应用体验。
139 15
|
3月前
|
Cloud Native Java API
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
Java Spring框架技术栈选和最新版本及发展史详解(截至2025年8月)-优雅草卓伊凡
635 0
|
消息中间件 NoSQL Java
使用Java构建可扩展的微服务架构
使用Java构建可扩展的微服务架构
|
监控 Java 持续交付
使用Java构建企业级微服务架构的策略与挑战
使用Java构建企业级微服务架构的策略与挑战