如果你在 Spring Boot 项目里做过 MongoDB 访问,大概率会有两种感受:
- 直接用
MongoTemplate很灵活,但查询条件、排序、分页、更新语义容易散落在业务代码里。 - 用 Spring Data Repository 能解决一部分样板代码问题,但一旦遇到复杂条件、聚合、批量更新、动态拼装查询,代码又会迅速回到“工具层很强,业务层很累”的状态。
这也是为什么很多 Java 开发者在使用 MongoDB 时,会想念 MyBatis-Plus 那种体验:
- 有统一的查询入口
- 有顺手的 Wrapper DSL
- 有声明式的 Mapper 抽象
- 有分页、批量、聚合这些常见能力
- 有
AutoMapper这类能减少模板代码的编译期能力 - 有方便二开的自定义 Mapper 方法扩展点
- 有可插拔插件机制来承接审计、埋点和治理能力
- 最好还能接进 Spring Boot 自动配置
mongo-plus 就是在这样的背景下出现的。
它不是去替代 Spring Data MongoDB,而是基于 Spring Data MongoDB 往上封装出一套更贴近业务开发的访问模型:把 Engine、Wrapper、Mapper、Aggregation、Plugin 和 APT 这些能力组合到一起,让 MongoDB 在 Spring Boot 里的开发体验更统一、更工程化。
而且现在它已经不只是仓库里的一个 SNAPSHOT 项目了,首个正式版 2026.1.0.0 已经发布到 Sonatype Central,这意味着它已经具备了一个可以被真实项目直接依赖和验证的发布形态。
一句话认识 mongo-plus
mongo-plus 是一个面向 Spring Boot 的 MongoDB 数据访问框架,它把引擎式查询入口与 MyBatis-Plus 风格的 Wrapper / Mapper 模型结合在一起,并提供聚合 DSL、执行拦截器、APT 常量生成以及 Spring Boot Starter 集成。
如果用一句更接地气的话来总结,它想解决的是:
在保留 Spring Data MongoDB 生态的前提下,让 MongoDB 的业务访问层写起来更像“有统一风格的框架”,而不是一组松散 API 的拼装。
mongo-plus 解决的核心问题
从当前仓库文档来看,mongo-plus 主要聚焦下面几类问题。
1. 给 MongoDB 查询一个统一入口
框架提供了非常明确的一条查询链路:
MongoEngine
-> QueryService
-> EngineQuery / LambdaEngineQuery
-> QueryWrapper / LambdaQueryWrapper
-> QueryExecutor
这条链路的价值在于,它让业务代码不必直接散落着各种 MongoTemplate 细节,而是通过 MongoEngine -> QueryService -> Query 的形式去组织查询逻辑。
这类写法尤其适合那些希望在 Service 层保留“查询服务边界”的团队。
2. 给条件构造、分页和更新一个统一 DSL
mongo-plus 的 Wrapper 设计和 MyBatis-Plus 很接近,常见能力包括:
QueryWrapperLambdaQueryWrapperUpdateWrapperLambdaUpdateWrapper
也就是说,你可以用一套统一的 fluent API 去表达:
- 条件过滤
- 排序
- 投影
limit / skip- 分页
- 按条件更新
这比在业务层里直接组装 Query、Criteria、Update 更容易复用,也更利于团队统一风格。
3. 给 CRUD 和批量操作一个声明式 Mapper 抽象
如果你习惯 MyBatis-Plus 风格的 Repository / Mapper 层,那么 MongoMapper<T> 会非常好理解。
最小定义就是这样:
import io.github.photowey.mongoplus.mapper.MongoMapper;
public interface UserMapper extends MongoMapper<UserDocument> {
}
不需要手写实现,运行时由 Spring Boot 自动配置和代理机制完成分发。
在这个抽象之上,框架把这些能力统一放到了 Mapper 路径中:
- 单体 CRUD
- 分页查询
- 批量写入 / 删除
- 聚合入口
4. 给聚合查询一个更接近业务代码的 DSL
MongoDB 的聚合能力很强,但原始管道在业务代码里往往不好维护。mongo-plus 为此提供了 AggregationWrapper<T>,可以用 DSL 方式表达 $match、$group、$project、排序和分页等阶段。
例如:
AggregationWrapper<UserDocument> wrapper = AggregationWrapper.aggregation(UserDocument.class)
.match(query -> query.gte(UserDocument::getAge, 18))
.group(UserDocument::getAge)
.count("total");
这类写法的优势很明显:聚合逻辑仍然是 MongoDB 语义,但组织方式已经是框架级 DSL,而不是一堆原始文档结构。
5. 给执行链路提供可插拔拦截能力
很多 MongoDB 项目发展到中后期,都会冒出横切需求:
- 记录查询链路
- 审计关键写操作
- 加埋点
- 做轻量鉴权
- 某些场景下短路执行
mongo-plus 为这类需求提供了 MongoPlusInterceptor SPI,并且可以作用在三种上下文上:
MapperInvocationContextQueryExecutionContextAggregationExecutionContext
这意味着你可以分别拦截 Mapper 调用、普通查询执行和聚合执行,而不用把这些逻辑硬塞进业务代码。
6. 给 AutoMapper 和字段元数据提供编译期支持,减少模板代码
mongo-plus 还提供了 mongo-plus-apt 模块,用于生成字段常量以及 @AutoMapper 相关产物。
这类能力的意义在于:
- 通过
@AutoMapper减少重复的模板代码 - 减少硬编码字符串字段名
- 支持元数据风格查询
- 让编译期生成承担一部分重复劳动
例如文档里就提供了这种写法:
UserDocument user = mongoEngine
.queryService()
.createQuery(UserDocument.class)
.eq(UserDocumentColumns.USER_NAME, "photowey")
.one();
如果团队非常在意字段重构安全性,这个点会很有价值。
而且这部分能力不是“锦上添花”的附属品。对很多业务项目来说,真正烦人的往往不是写一条查询,而是围绕实体、字段、映射辅助产物反复写样板代码。mongo-plus 把这部分工作前移到了 APT 阶段,这一点非常适合长期维护的项目。
7. 给 Mapper 二开提供正式扩展点,而不是逼你绕过框架
很多框架的 Mapper 只能使用内置 CRUD,一旦你想扩展,就只能自己另起一套实现。
mongo-plus 在这一点上做得更工程化。它支持通过 MethodHandlerRegistryCustomizer 给 Mapper 代理注册自定义方法处理器,也就是说,你可以在不破坏原有 Mapper 模型的前提下,把业务定制能力扩进去。
示意代码如下:
@Bean
public MethodHandlerRegistryCustomizer findByStatusCustomizer() {
return registry -> registry.addInjector(new AbstractMethod() {
@Override
public String getMethodName() {
return "findByStatus";
}
@Override
protected Command getCommand() {
return Command.SELECT;
}
@Override
protected MethodHandler createHandler() {
return (getter, entityClass, args) -> {
if (args != null && args.length > 0 && args[0] != null) {
return "ok:" + args[0];
}
return "ok:null";
};
}
});
}
然后你只需要在 Mapper 接口里声明同名方法:
@MongoMapper
public interface CustomMethodMapper {
String findByStatus(String status);
}
这件事的意义很大,因为它说明 mongo-plus 的 Mapper 不是“只能用官方内置能力”的封闭模型,而是支持业务侧二次开发和自定义命令注入的开放模型。
mongo-plus 的几个关键设计点
很多框架介绍文章只讲“怎么用”,不讲“为什么这样设计”。但 mongo-plus 当前仓库其实已经把设计边界整理得比较清楚了。
1. 它不是替代 Spring Data MongoDB,而是站在它上面
从执行层文档可以看出,mongo-plus 的底层仍然建立在 MongoTemplate 之上。也就是说,它没有绕开 Spring Data MongoDB,而是在其上增加了一层更适合业务开发的抽象。
可以简单理解成:
- Spring Data MongoDB 提供底层能力
mongo-plus提供更统一的业务访问模型
这类路线比“完全另起炉灶”更现实,也更容易落地到现有 Spring Boot 项目中。
2. 它把 DSL、编译和执行分层了
项目里有几个很关键的模块边界:
mongo-plus-dsl:定义条件 DSL、查询整形 DSL 和 AST 模型mongo-plus-wrapper:承载 Query / Update Wrapper 的状态构建mongo-plus-query:查询构建和 AST 编译支持mongo-plus-executor:把 Wrapper / Query / Pipeline 变成真正可执行的 MongoDB 操作
也就是说,它并不是简单把一堆链式调用直接拼成最终查询,而是走了一个更清晰的分层模型:
Wrapper / EngineQuery
-> AST / Query Model
-> Compiler
-> Query / Aggregation
-> MongoTemplate
这种设计的好处是:
- DSL 和执行层解耦
- 查询语义更容易统一
- 未来做优化、插件扩展、调试分析的空间更大
3. 它同时照顾两类团队习惯
这是我觉得 mongo-plus 很实用的一点。
很多团队对数据访问层的偏好并不一样:
- 有的团队喜欢显式 Query Service,强调服务边界
- 有的团队喜欢 Mapper 风格,强调声明式 CRUD 和短路径调用
mongo-plus 没有强迫大家只能选一种,而是同时提供了两条主路径:
Engine路径:MongoEngine -> QueryService -> QueryMapper + Wrapper路径:MongoMapper<T> + Wrappers
这使它在项目落地时更灵活,也更容易被不同开发习惯的团队接受。
从使用者视角看,mongo-plus 有哪些亮点
如果你只站在“我要不要在项目里试一下”这个角度,我认为它最值得关注的是下面几个点。
1. 上手成本不高
对 Spring Boot 项目来说,接入方式非常直接。
Spring Boot 2.x:
<dependency>
<groupId>io.github.photowey</groupId>
<artifactId>mongo-plus-spring-boot-starter</artifactId>
<version>2026.1.0.0</version>
</dependency>
Spring Boot 3.x:
<dependency>
<groupId>io.github.photowey</groupId>
<artifactId>mongo-plus-spring-boot3-starter</artifactId>
<version>2026.1.0.0</version>
</dependency>
基础配置也基本沿用 Spring Data MongoDB:
spring:
data:
mongodb:
uri: mongodb://localhost:27017/mongo_plus
2. 对 MyBatis-Plus 用户很友好
如果你本来就习惯 MyBatis-Plus 的这些模式:
Mapper<T>Wrapper- Lambda 条件构造
- 分页模型
那 mongo-plus 的 API 心智成本会低很多。
比如查询成年人用户:
List<UserDocument> users = userMapper.selectList(
Wrappers.<UserDocument>lambdaQuery(UserDocument.class)
.gte(UserDocument::getAge, 18)
.orderByDesc(UserDocument::getId)
);
比如按条件更新:
boolean updated = userMapper.update(
null,
Wrappers.<UserDocument>lambdaUpdate(UserDocument.class)
.eq(UserDocument::getId, 1L)
.set(UserDocument::getEmail, "next@example.com")
.inc(UserDocument::getAge, 1)
);
这类写法对于很多 Java 后端来说是天然顺手的。
3. Engine 路径很适合复杂业务服务
如果你不希望 Service 层直接依赖 Mapper,也可以走 Engine 路径:
List<UserDocument> users = mongoEngine
.queryService()
.createLambdaQuery(UserDocument.class)
.eq(UserDocument::getName, "photowey")
.gte(UserDocument::getAge, 18)
.orderByDesc(UserDocument::getId)
.list();
这条路径的优势是,业务代码读起来像一个明确的查询服务,而不是“Repository 上直接堆功能”。
4. 聚合、分页、批量这些高频需求都被纳入统一模型
很多 MongoDB 框架在简单查询上做得不错,但一碰到分页、聚合、批量写入,就又把开发者扔回原生 API。
mongo-plus 现在已经把这些能力统一纳入同一个框架模型:
- 分页:
Page<T> - 批量:
BatchResult - 聚合:
AggregationWrapper<T>
这意味着你不需要为不同场景切换完全不同的编程风格。
5. 扩展点是实打实可落地的
这不是一个只有“主路径 API”而没有扩展空间的框架。
当前文档里已经明确给出了三类非常实用的扩展机制:
@AutoMapper+mongo-plus-aptMongoPlusInterceptorMethodHandlerRegistryCustomizer
第一类解决“减少模板代码”的问题,第二类解决执行链路横切,第三类解决自定义 Mapper 方法注册。
这对中大型项目尤其关键,因为真正难的从来不是 CRUD,而是“框架能不能跟着业务演进”。
6. 插件 SPI 不是摆设,确实适合承接治理能力
如果只从业务 CRUD 的角度看,插件机制似乎不是第一眼能感知到的能力。
但只要项目一进入团队协作和线上治理阶段,插件能力的重要性就会迅速放大。mongo-plus 提供的 MongoPlusInterceptor 可以在 Mapper、Query、Aggregation 三条执行链路上工作,这意味着下面这些事情都有了统一挂点:
- 查询链路追踪
- 审计关键写操作
- 指标统计和埋点
- 轻量级开关控制
- 特定场景的短路返回
注册方式也比较直接:
@Bean
public MongoPlusInterceptor tracingInterceptor() {
return new MongoPlusInterceptor() {
@Override
public int getOrder() {
return 10;
}
@Override
public boolean supports(InvocationContext context) {
return context instanceof QueryExecutionContext;
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
};
}
这意味着插件不是一个“以后再说”的保留接口,而是当前框架已经明确纳入执行模型的一等能力。
一个最小可运行示例
如果你想快速感受 mongo-plus 的使用方式,可以从下面这套最小示例开始。
1. 定义实体
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import io.github.photowey.mongoplus.annotation.MongoId;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "users")
public class UserDocument implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@MongoId(type = MongoId.IdType.ASSIGN_ID)
private Long id;
private String name;
private String email;
private Integer age;
}
2. 定义 Mapper
import io.github.photowey.mongoplus.mapper.MongoMapper;
public interface UserMapper extends MongoMapper<UserDocument> {
}
3. 开启 Mapper 扫描
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import io.github.photowey.mongoplus.autoconfigure.core.annotation.MongoMapperScan;
@SpringBootApplication
@MongoMapperScan(basePackages = "com.example.user.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
4. 在 Service 里查询
import java.util.List;
import org.springframework.stereotype.Service;
import io.github.photowey.mongoplus.wrapper.core.util.Wrappers;
@Service
public class UserService {
private final UserMapper userMapper;
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public List<UserDocument> findAdults() {
return this.userMapper.selectList(
Wrappers.<UserDocument>lambdaQuery(UserDocument.class)
.gte(UserDocument::getAge, 18)
.orderByDesc(UserDocument::getId)
);
}
}
到这里,你已经可以用一种接近 MyBatis-Plus 的方式去操作 MongoDB 了。
5. 可选:开启 AutoMapper
如果你希望把一部分重复代码交给编译期生成,可以引入 mongo-plus-apt,并在实体上标注 @AutoMapper:
import io.github.photowey.mongoplus.annotation.AutoMapper;
@AutoMapper
@Document(collection = "generated_users")
public class GeneratedUserDocument {
}
这条能力的核心价值不是“多一个注解”,而是把一部分字段元数据和映射相关的模板代码从手写迁移到生成,减少重复劳动。
它适合什么项目
结合当前仓库文档和模块设计,我认为 mongo-plus 比较适合下面几类项目。
1. Spring Boot + MongoDB 的业务系统
尤其是那些业务层代码比较重、需要统一访问风格的项目。
2. 既想保留 Spring Data MongoDB,又想提升开发体验的团队
如果你不想放弃 Spring 生态,但又觉得原生 MongoTemplate 太散,mongo-plus 会是一个很自然的增强层。
3. 对 MyBatis-Plus 编程模型比较熟悉的 Java 团队
这类团队迁移认知的成本最低,通常一看 Mapper + Wrapper + LambdaQuery 就能进入状态。
4. 需要聚合、分页、批量和拦截器扩展的项目
如果你的项目已经不仅仅是“查一条数据、改一个字段”,而是进入了更复杂的数据访问场景,那它提供的统一模型会更有价值。
5. 希望保留二开能力的框架型项目
如果你的团队很在意“现在能不能用”和“以后能不能扩”,那么 mongo-plus 的自定义 Mapper 方法和插件 SPI 会比单纯的 CRUD API 更有吸引力。
现阶段我最看重的价值
如果让我用几句话总结 mongo-plus 的价值,我会这样说:
- 它让 MongoDB 在 Spring Boot 里的访问层更像一个完整框架,而不是一组零散能力。
- 它把 MyBatis-Plus 风格的使用体验迁移到了 MongoDB 场景里,而且不是只停留在 CRUD,而是把聚合、分页、批量和插件也纳入了统一设计。
- 它提供了
AutoMapper和 APT 支持,可以把一部分重复的模板代码前移到编译期处理。 - 它的 Mapper 不只是声明式 CRUD 入口,还支持通过自定义方法注册机制做二开扩展。
- 它底层仍然站在 Spring Data MongoDB 之上,因此接入成本和生态兼容性都比较现实。
- 它在 DSL、编译、执行、插件这几个层次上做了清晰分层,这说明它的目标不只是“能用”,而是“能持续演进”。
当然,任何框架最终都要回到一个问题:是否适合你的团队。
如果你的项目非常轻量,只有少量 MongoDB 读写,直接用 MongoTemplate 可能已经足够。
但如果你的项目已经出现这些信号:
- 查询和更新逻辑越来越多
- 业务代码里开始堆积 MongoDB 细节
- 团队希望统一查询风格
- 需要分页、聚合、批量和拦截能力
那么 mongo-plus 值得认真看一遍。
结尾
MongoDB 在 Java 生态里并不缺底层能力,缺的是一套足够顺手、足够统一、又能兼顾工程扩展性的上层开发模型。
但 mongo-plus 正在尝试补上这块空白。
如果你正在做 Spring Boot + MongoDB 项目,并且希望获得更接近 MyBatis-Plus 的开发体验,同时又不想脱离 Spring Data MongoDB 生态,那么 mongo-plus 是一个值得关注的方向。
如果你准备自己试一下,推荐按这个顺序上手:
- 引入对应的 Spring Boot Starter
- 定义一个实体和
MongoMapper<T> - 打开
@MongoMapperScan - 先跑最简单的
lambdaQuery - 再逐步尝试分页、聚合、拦截器和 APT
目前首个正式版已经发布到 Sonatype Central:
io.github.photowey:mongo-plus- 版本:
2026.1.0.0 - 地址:传送门
本文基于当前仓库文档整理,并结合已发布的 2026.1.0.0 release 版本进行了更新。