# litejava **Repository Path**: isee00/litejava ## Basic Information - **Project Name**: litejava - **Description**: No description available - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-12-27 - **Last Updated**: 2026-03-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # LiteJava

🚀 极简 Java Web 框架
性能比肩 Go,轻量高效,插件化扩展,无缝融合 Java 生态

快速开始为什么选择核心特性插件生态性能测试

--- ## 30 秒上手 ```java import litejava.*; import litejava.plugins.LiteJava; import litejava.util.Maps; public class Main { public static void main(String[] args) { App app = LiteJava.create(); app.get("/", ctx -> ctx.json(Maps.of("message", "Hello, LiteJava!"))); app.get("/users/:id", ctx -> { long id = ctx.pathParamLong("id"); ctx.json(Maps.of("id", id, "name", "User " + id)); }); app.run(); // 启动!访问 http://localhost:8080 } } ``` **就这么简单。** 没有 XML,没有注解地狱,没有 30 秒的启动等待。 --- ## 为什么选择 LiteJava? ### 🎯 如果你厌倦了... - **Spring Boot 的臃肿** - 启动 10 秒,内存 500MB,一个 Hello World 引入 100+ 依赖 - **注解的泛滥** - `@RestController` `@RequestMapping` `@Autowired` `@Service` `@Component`... - **魔法般的自动装配** - 出了问题不知道哪里错,堆栈 50 层看不懂 - **配置的复杂** - application.yml 写了 200 行还没配完 ### ✨ LiteJava 给你... | 痛点 | Spring Boot | LiteJava | |------|-------------|----------| | 启动时间 | 3-10 秒 | **< 500ms** | | 内存占用 | 200-500 MB | **30-80 MB** | | JAR 大小 | 30-100 MB | **< 1 MB** (core) | | 依赖数量 | 100+ | **0** (core) | | 学习曲线 | 陡峭(注解+约定太多) | **平缓**(代码即配置) | | 调试难度 | 困难(魔法太多) | **简单**(所见即所得) | --- ## 核心特性 ### 1️⃣ Gin-style 路由 ```java // 基础路由 app.get("/users", ctx -> ctx.json(userService.list())); app.post("/users", ctx -> ctx.json(userService.create(ctx.bindJSON()))); app.put("/users/:id", ctx -> ctx.json(userService.update(ctx.pathParamLong("id"), ctx.bindJSON()))); app.delete("/users/:id", ctx -> ctx.ok(userService.delete(ctx.pathParamLong("id")))); // 路由分组 - 告别重复前缀 app.group("/api/v1", api -> { api.get("/books", BookController::list); // GET /api/v1/books api.post("/books", BookController::create); // POST /api/v1/books api.get("/books/:id", BookController::get); // GET /api/v1/books/:id }); // 嵌套分组 + 分组级中间件 app.group("/admin", admin -> { admin.use(new AuthPlugin(token -> jwtPlugin.verify(token))); // 只对 /admin/* 生效 admin.group("/users", users -> { users.get("/", UserController::list); users.delete("/:id", UserController::delete); }); }); // 通配符路由 app.get("/files/*filepath", ctx -> ctx.file(new File(uploadDir, ctx.pathParam("filepath")))); ``` ### 2️⃣ Koa-style 洋葱中间件 ```java // 请求日志中间件 app.use((ctx, next) -> { long start = System.currentTimeMillis(); System.out.println("--> " + ctx.method + " " + ctx.path); next.run(); // 执行后续中间件和 handler long cost = System.currentTimeMillis() - start; System.out.println("<-- " + ctx.status + " " + cost + "ms"); }); // 认证插件 - 使用内置 AuthPlugin app.use(new AuthPlugin(token -> { // 自定义验证逻辑,返回用户信息 Map 或 null return jwtPlugin.verify(token); }).whitelist("/", "/login").whitelistPrefix("/static")); // 在 Handler 中获取认证信息 app.get("/api/me", ctx -> { Map user = (Map) ctx.state.get("auth"); ctx.ok(user); }); ``` ### 3️⃣ 简洁的 Context API ```java app.post("/users", ctx -> { // 获取参数 String name = ctx.queryParam("name"); // 查询参数 int page = ctx.queryParamInt("page", 1); // 带默认值 long id = ctx.pathParamLong("id"); // 路径参数 String token = ctx.header("Authorization"); // 请求头 User user = ctx.bindJSON(User.class); // JSON 请求体 // 响应 ctx.ok(data); // {"code":0, "data":..., "msg":"success"} ctx.fail("error message"); // {"code":-1, "msg":"error message"} ctx.json(obj); // 原始 JSON ctx.text("hello"); // 纯文本 ctx.html("

Hi

"); // HTML ctx.redirect("/login"); // 重定向 ctx.file(new File("doc.pdf")); // 文件下载 ctx.render("user.html", model); // 模板渲染 }); ``` ### 4️⃣ 万物皆插件 **不强制任何功能,自由装配你需要的插件:** ```java // 最小化启动 - 只要路由和服务器 App app = new App(); app.use(new HttpServerPlugin()); app.get("/", ctx -> ctx.text("Hello")); app.run(); // 按需添加功能 app.use(new JacksonPlugin()); // 需要 JSON? app.use(new JdbcPlugin()); // 需要数据库? app.use(new RedisCachePlugin()); // 需要缓存? app.use(new ThymeleafPlugin()); // 需要模板? app.use(new SwaggerPlugin()); // 需要 API 文档? // 或者一键启动(预装常用插件) App app = LiteJava.create(); // 包含 Jackson + MemoryCache + HttpServer ``` **插件可随时替换,对业务代码零影响:** ```java // 开发环境:用内置 HttpServer app.use(new HttpServerPlugin()); // 生产环境:换成 Netty 高性能服务器 app.use(new NettyServerPlugin()); // 或者用虚拟线程版本 (Java 21+) app.use(new JdkVirtualThreadServerPlugin()); ``` **有趣的工具插件,开发调试更轻松:** ```java // DebugPlugin - 启动时打印应用结构 app.use(new DebugPlugin()); // 输出: // ╔══════════════════════════════════════════════════════════════╗ // ║ My Application ║ // ╠══════════════════════════════════════════════════════════════╣ // ║ Plugins (6): ║ // ║ 1. Slf4jLogPlugin ║ // ║ 2. JacksonPlugin ║ // ║ 3. HttpServerPlugin ║ // ╠══════════════════════════════════════════════════════════════╣ // ║ Middleware Chain (2): ║ // ║ Request → [ExceptionPlugin] → [CorsPlugin] → Handler ║ // ╚══════════════════════════════════════════════════════════════╝ ``` **配置也可以装在插件里:** ```java // 默认:.properties 配置 app.use(new ConfPlugin()); // app.conf.get("key") // 想用 YAML?换个插件 app.use(new YamlConfPlugin()); // 同样的 API,不同的配置格式 // 想从环境变量读取?自己写个插件 app.use(new EnvConfPlugin()); // 插件机制让扩展变得简单 ``` --- ## 真实项目示例 ### RESTful API 服务 ```java public class BookApp { public static void main(String[] args) { App app = LiteJava.create(); // 数据库 HikariPlugin hikari = new HikariPlugin(); app.use(hikari); JdbcPlugin jdbc = new JdbcPlugin(hikari); app.use(jdbc); // 图书 CRUD app.group("/api/books", books -> { books.get("/", ctx -> { int page = ctx.queryParamInt("page", 1); int size = ctx.queryParamInt("size", 20); List> list = jdbc.jdbcTemplate.queryForList( "SELECT * FROM books LIMIT ? OFFSET ?", size, (page - 1) * size ); ctx.ok(Maps.of("data", list, "page", page, "size", size)); }); books.get("/:id", ctx -> { Map book = jdbc.jdbcTemplate.queryForMap( "SELECT * FROM books WHERE id = ?", ctx.pathParamLong("id") ); ctx.ok(book); }); books.post("/", ctx -> { Map data = ctx.bindJSON(); jdbc.jdbcTemplate.update( "INSERT INTO books (title, author) VALUES (?, ?)", data.get("title"), data.get("author") ); ctx.ok("created"); }); books.delete("/:id", ctx -> { jdbc.jdbcTemplate.update("DELETE FROM books WHERE id = ?", ctx.pathParamLong("id")); ctx.ok("deleted"); }); }); app.run(); } } ``` ### 带认证的微服务 ```java public class UserService { public static void main(String[] args) { App app = LiteJava.create(); app.use(new JwtPlugin("your-secret-key")); app.use(new ValidationPlugin()); app.use(new SwaggerPlugin().scanPackages("com.example.controller")); // 公开接口 app.post("/auth/login", ctx -> { Map body = ctx.bindJSON(); String token = JwtPlugin.instance.sign(Maps.of("userId", 123)); ctx.ok(Maps.of("token", token)); }); // 需要认证的接口 app.group("/api", api -> { api.use(new AuthPlugin(token -> JwtPlugin.instance.verify(token))); api.get("/me", ctx -> { Map user = (Map) ctx.state.get("auth"); ctx.ok(user); }); api.put("/me", ctx -> { // 参数校验 Map body = ctx.bindJSON(); ValidationPlugin.instance.validate(body, Maps.of( "name", "required|min:2|max:50", "email", "required|email" )); ctx.ok("updated"); }); }); app.run(); } } ``` --- ## 插件生态 ### 核心模块 (litejava-core) - 零依赖 | 插件 | 说明 | |------|------| | `RouterPlugin` | Radix Tree 路由,支持分组、通配符、路径参数 | | `HttpServerPlugin` | 基于 JDK 内置 HttpServer | | `ConfPlugin` | .properties 配置文件 | | `LogPlugin` | 简单日志输出 | | `JsonPlugin` | 零依赖 JSON 解析/序列化 | | `StaticFilePlugin` | 静态文件服务 | | `ViewPlugin` | 视图渲染基类 | ### 可选插件 (litejava-plugins) | 分类 | 插件 | 说明 | |------|------|------| | **服务器** | `NettyServerPlugin` | Netty 高性能服务器 | | | `JettyServerPlugin` | Jetty 服务器 | | | `UndertowServerPlugin` | Undertow 服务器 | | **数据源** | `HikariPlugin` | HikariCP 连接池(推荐) | | | `DruidPlugin` | Druid 连接池 | | **数据库** | `JdbcPlugin` | JDBC 数据库访问 | | | `JpaPlugin` | JPA ORM | | | `MyBatisPlugin` | MyBatis 集成 | | **缓存** | `MemoryCachePlugin` | 内存缓存 | | | `RedisCachePlugin` | Redis 缓存 | | **JSON** | `JacksonPlugin` | Jackson JSON | | **模板** | `ThymeleafPlugin` | Thymeleaf 模板 | | | `FreemarkerPlugin` | Freemarker 模板 | | **安全** | `JwtPlugin` | JWT 认证 | | | `SessionPlugin` | Session 管理 | | | `CorsPlugin` | 跨域处理 | | | `CsrfPlugin` | CSRF 防护 | | | `RateLimitPlugin` | 限流 | | **校验** | `ValidationPlugin` | Bean Validation (JSR-380) | | **DI** | `GuicePlugin` | Google Guice 依赖注入 | | **定时任务** | `SchedulePlugin` | Quartz 定时任务 | | **API 文档** | `SwaggerPlugin` | OpenAPI/Swagger 文档 | | **监控** | `MetricsPlugin` | Micrometer 指标 | | | `TracingPlugin` | 链路追踪 | | **其他** | `WebSocketPlugin` | WebSocket 支持 | | | `GraphQLPlugin` | GraphQL 查询 | ### 虚拟线程插件 (litejava-plugins-vt) - Java 21+ | 插件 | 说明 | |------|------| | `JdkVirtualThreadServerPlugin` | JDK HttpServer + 虚拟线程 | | `JettyVirtualThreadServerPlugin` | Jetty + 虚拟线程 | --- ## 性能测试 **🔥 性能比肩 Go 语言框架,部分场景甚至超越 Gin** > 测试环境:Windows 11, AMD Ryzen 9 5900HX, 32GB RAM, JDK 21 > 测试工具:wrk -t4 -c100 -d30s ### JSON 响应 (GET /json) | 框架 | QPS | 平均延迟 | P99 延迟 | |------|-----|---------|---------| | **LiteJava (Netty)** | **152,847** | **0.65ms** | **2.1ms** | | **LiteJava (JDK+VT)** | **148,523** | **0.67ms** | **2.3ms** | | Gin (Go) | 141,235 | 0.71ms | 2.5ms | | Javalin | 125,634 | 0.79ms | 3.2ms | | Spring Boot | 45,123 | 2.21ms | 8.5ms | ### 数据库查询 (GET /users) | 框架 | QPS | 平均延迟 | P99 延迟 | |------|-----|---------|---------| | **LiteJava (Netty)** | **28,456** | **3.5ms** | **12ms** | | **LiteJava (JDK+VT)** | **31,234** | **3.2ms** | **10ms** | | Gin (Go) | 26,789 | 3.7ms | 13ms | | Javalin | 24,567 | 4.1ms | 15ms | | Spring Boot | 12,345 | 8.1ms | 32ms | ### 启动时间 & 内存 | 框架 | 启动时间 | 内存占用 | |------|---------|---------| | **LiteJava** | **~200ms** | **~40MB** | | Gin (Go) | ~50ms | ~15MB | | Javalin | ~800ms | ~80MB | | Spring Boot | ~3500ms | ~250MB | --- ## 快速开始 ### Maven ```xml jitpack.io https://jitpack.io com.github.isee22.litejava litejava-core v1.0.0-jdk8 com.github.isee22.litejava litejava-plugins v1.0.0-jdk8 com.github.isee22.litejava litejava-plugins-vt v1.0.0-jdk21 ``` ### 模块说明 | 模块 | JDK | 说明 | |------|-----|------| | litejava-core | 8+ | 核心模块,零依赖 | | litejava-plugins | 8+ | 可选插件(JSON、数据库、缓存等) | | litejava-plugins-vt | 21+ | 虚拟线程插件 | --- ## 自定义插件 创建自己的插件非常简单: ```java public class MyPlugin extends Plugin { public static MyPlugin instance; @Override public void config() { instance = this; // 初始化逻辑 app.log.info("MyPlugin loaded!"); // 可以注册路由 app.get("/my-plugin/status", ctx -> ctx.ok("running")); // 可以添加中间件 app.use((ctx, next) -> { ctx.header("X-My-Plugin", "1.0"); next.run(); }); } @Override public void uninstall() { // 清理逻辑 instance = null; } // 插件提供的功能 public void doSomething() { // ... } } // 使用 app.use(new MyPlugin()); MyPlugin.instance.doSomething(); ``` --- ## 框架对比 ### 什么时候用 LiteJava? ✅ **适合场景:** - 微服务、API 服务 - 追求轻量和快速启动 - 厌倦了 Spring Boot 的复杂 - 想要 Go/Gin 风格的 Java 开发体验 - 需要精确控制依赖 - 快速原型开发 ❌ **不适合场景:** - 团队只会 Spring,不想学新东西 - 需要 Spring 生态的特定功能 - 企业级大型单体应用 ### vs Spring Boot - 深度对比 Spring Boot 确实解决了很多问题,但代价是什么?LiteJava 用更轻量的方式提供同样的能力: | Spring 解决的问题 | Spring 的方式 | LiteJava 的方式 | |------------------|--------------|----------------| | **依赖注入 (DI)** | `@Autowired` + 容器扫描,启动慢 | `GuicePlugin` 可选集成,或直接构造函数传参 | | **路由映射** | `@RequestMapping` 注解,分散在各类 | 代码集中定义 `app.get("/path", handler)` | | **配置管理** | `@Value` + `@ConfigurationProperties` | `ConfPlugin` 读取,`app.conf.get("key")` | | **数据库访问** | `@Repository` + Spring Data | `JdbcPlugin` / `MyBatisPlugin` 插件 | | **事务管理** | `@Transactional` 注解 | `JdbcPlugin.transaction(conn -> {...})` | | **缓存** | `@Cacheable` + 自动代理 | `RedisCachePlugin` 显式调用 | | **参数校验** | `@Valid` + `@NotNull` | `ValidationPlugin` 可选,代码校验同样简洁 | | **AOP 切面** | `@Aspect` + 动态代理 | 中间件 `app.use((ctx, next) -> {...})` | | **定时任务** | `@Scheduled` | `SchedulePlugin` 插件 | | **API 文档** | Springfox/SpringDoc 注解 | `SwaggerPlugin` 插件 | **关键区别:** - **Spring**:功能深度绑定框架,注解侵入业务代码,移除困难 - **LiteJava**:功能以插件形式提供,对框架核心零侵入,随时可插拔 ```java // Spring 方式 - 注解侵入业务代码 @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @Autowired private CacheManager cache; @GetMapping("/{id}") @Cacheable("users") public User getUser(@PathVariable Long id) { return userService.findById(id); } } // LiteJava 方式 - 代码即配置,无侵入 app.get("/users/:id", ctx -> { long id = ctx.pathParamLong("id"); User user = cache.get("user:" + id, () -> userService.findById(id)); ctx.ok(user); }); ``` **即使需要注解,LiteJava 也能通过插件无侵入地支持:** ```java // 想用 JSR-330 依赖注入?加个插件 app.use(new GuicePlugin()); // 想用 Bean Validation?加个插件 app.use(new ValidationPlugin()); // 想用 JPA 注解?加个插件 app.use(new JpaPlugin()); // 不想用了?移除插件即可,业务代码无需改动 ``` | | Spring Boot | LiteJava | |--|-------------|----------| | 理念 | 约定优于配置 | 代码即配置 | | 优势 | 企业级支持、社区成熟 | 轻量快速、代码透明、插件灵活 | | 劣势 | 臃肿、魔法多、启动慢、注解侵入 | 社区较新 | ### 关于"Spring 生态丰富"的真相 很多人说 Spring 生态丰富,但仔细想想: **Spring 的"生态"本质是什么?** ``` Spring Boot + spring-boot-starter-xxx + 第三方库 ``` starter 只是**桥接代码**,把第三方库包装成 Spring 风格。你用的还是那个第三方库,只是被 Spring "圈"进了它的体系。 **LiteJava 直接用第三方库原生 API:** ```java // Spring 方式:需要 spring-boot-starter-data-redis + 配置 + @Autowired @Autowired private RedisTemplate redisTemplate; redisTemplate.opsForValue().set("key", "value"); // LiteJava 方式:直接用 Jedis,3 行代码 Jedis jedis = new Jedis("localhost", 6379); jedis.set("key", "value"); jedis.close(); ``` ```java // Spring 方式:需要 spring-boot-starter-amqp + 配置 + @RabbitListener @RabbitListener(queues = "myQueue") public void listen(String message) { ... } // LiteJava 方式:直接用 RabbitMQ 官方客户端 ConnectionFactory factory = new ConnectionFactory(); Connection conn = factory.newConnection(); Channel channel = conn.createChannel(); channel.basicConsume("myQueue", (tag, msg) -> { ... }, tag -> {}); ``` **Java 生态的库本来就是给所有 Java 程序用的**,Spring 反而是把它们"圈"进自己的体系,还要你学一套 Spring 特有的 API。 LiteJava 让你回归 Java 本身。 ### vs Javalin | | Javalin | LiteJava | |--|---------|----------| | 理念 | 简单 Web 框架 | 插件化框架 | | 优势 | API 简洁、文档友好 | 插件生态、服务器可选 | | 劣势 | 功能固定、绑定 Jetty | 相对较新 | ### vs Gin (Go) | | Gin | LiteJava | |--|-----|----------| | 语言 | Go | Java | | 性能 | 极致 | **比肩 Go(见性能测试)** | | 优势 | 内存极小 | 插件生态丰富、扩展性强、Java 库无缝集成 | | 劣势 | 扩展能力有限、需要学 Go | 内存占用略高 | --- ## 📚 文档 | 文档 | 说明 | |------|------| | [快速入门](docs/quick-start.md) | 5 分钟上手 LiteJava | | [插件开发指南](docs/plugin-guide.md) | 如何开发自定义插件 | | [最佳实践](docs/best-practices.md) | 项目结构、代码规范 | | [性能调优](docs/performance.md) | 服务器选择、JVM 调优 | | [Spring Boot 迁移](docs/spring-migration.md) | 从 Spring Boot 迁移到 LiteJava | --- ## 唯一推荐模式(Go/Gin 风格) LiteJava 推荐并约束为一条主路径: 1. **构建期完成所有装配**:插件、路由、中间件、回调都在 `run()` 前完成 2. **运行期不再改结构**:`run()` 后禁止增删插件和注册新路由 3. **依赖显式传递**:在启动阶段构造依赖,通过闭包/构造函数传给 handler 4. **避免容器查找式编程**:不推荐在业务代码里按名称/类型动态查找依赖 推荐写法: ```java App app = LiteJava.create(); JdbcPlugin jdbc = new JdbcPlugin(dataSource); app.use(jdbc); app.get("/users/:id", ctx -> { long id = ctx.pathParamLong("id"); ctx.ok(jdbc.jdbcTemplate.queryForMap("SELECT * FROM users WHERE id = ?", id)); }); app.run(); ``` 这能确保团队代码风格统一、行为可预测、排障路径清晰。 ## 设计哲学 > "Less is more" - 少即是多 - **代码即配置** - 路由、中间件、配置都用代码,不用注解 - **零魔法** - 所见即所得,无隐藏规则 - **零依赖** - 核心模块不依赖任何第三方库 - **显式优于隐式** - 明确胜过猜测 - **组合优于继承** - 插件组合而非类继承 ### 注解策略 LiteJava 不是完全禁止注解,而是控制边界: | 层级 | 策略 | 说明 | |------|------|------| | 路由/中间件 | ❌ 不用 | `app.get("/users", handler)` | | 配置 | ❌ 不用 | 配置文件 + 代码读取 | | DI | ✅ 可选 | `@Inject`, `@Singleton` (JSR-330) | | ORM | ✅ 可选 | `@Entity`, `@Table` (JPA) | | 校验 | ✅ 可选 | `@NotNull`, `@Size` (Bean Validation) | | API 文档 | ✅ 可选 | `@Operation`, `@Tag` (Swagger) | **反对的是**:Spring 式注解泛滥,一个类堆十几个注解 **接受的是**:数据层/基础设施层的标准注解,简单明确 --- ## 核心规则:配置文件优先 **这是 LiteJava 唯一需要了解的"隐性规则",理解它就没有任何魔法。** ### 配置优先级(从高到低) 1. **use() 后直接设置字段** - 最高优先级,强制覆盖 2. **配置文件** (application.yml / application.properties) 3. **代码构造参数** 4. **字段默认值** ### 为什么配置文件优先? 与 Spring Boot 一致,遵循"配置外部化"原则: - 代码里写的是"默认值" - 运维可以通过配置文件覆盖,无需改代码 - 便于不同环境(dev/test/prod)使用不同配置 ### 示例 ```java // 场景 1:构造函数传参会被配置文件覆盖 app.use(new HttpServerPlugin(9000)); // 传入 9000 // 但配置文件有 server.port=8080 // 最终使用 8080(配置文件优先) // 场景 2:如需代码强制指定,在 use() 后设置 HttpServerPlugin server = new HttpServerPlugin(); app.use(server); // config() 在此执行,读取配置文件 server.port = 9000; // 直接覆盖,最终使用 9000 // 场景 3:配置文件没有该配置项 app.use(new HttpServerPlugin(9000)); // 传入 9000 // 配置文件没有 server.port // 最终使用 9000(构造参数作为默认值) ``` ### 实现原理 插件的 `config()` 方法在 `app.use()` 时立即执行: ```java public class ServerPlugin extends Plugin { public int port = 8080; // 字段默认值 public ServerPlugin(int port) { this.port = port; // 构造参数覆盖默认值 } @Override public void config() { // 配置文件有值则覆盖,没有则保持当前值 port = app.conf.getInt("server", "port", port); } } ``` 执行顺序: 1. `new ServerPlugin(9000)` → port = 9000 2. `app.use(server)` → 调用 `config()` 3. `config()` 读取配置文件,有值则覆盖 → port = 8080 4. `server.port = 9000` → 直接覆盖 → port = 9000 --- ## 贡献 欢迎提交 Issue 和 PR! ## License MIT