工程实践
Maven / Gradle 命令、JUnit 5、SLF4J、打包、模块系统、LTS 选择
为什么需要工程化
学语法只能写小脚本。真正的项目需要:依赖管理(不手动下 jar)、自动化测试(不靠手点)、统一日志(不靠 System.out)、可部署的产物(不靠源码)、版本选择策略(决定 LTS)。本章覆盖 Java 后端开发每天都用的工具链。
Maven:依赖管理 + 构建(最主流)
应用场景:90% 的 Java 项目,特别是 Spring 系。一个 pom.xml 描述项目、依赖、插件,命令行 mvn 一键构建/测试/打包。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myapp</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>$ mvn compile # 编译 src/main/java
$ mvn test # 编译 + 跑 src/test/java
$ mvn package # 编译 + 测试 + 打 target/*.jar
$ mvn install # 装到本地 ~/.m2 仓库(供其它本地项目依赖)
$ mvn dependency:tree # 依赖树,定位版本冲突
$ mvn clean package # 先清 target/ 再打包Gradle:现代 + 灵活
Gradle 也是主流(Android 默认、Spring Boot 官方两套都支持)。脚本是 Groovy / Kotlin DSL,比 XML 紧凑。新项目可二选一——团队习惯什么就用什么。
// build.gradle.kts (Kotlin DSL)
plugins {
java
application
}
group = "com.example"
version = "1.0.0"
java { sourceCompatibility = JavaVersion.VERSION_17 }
repositories { mavenCentral() }
dependencies {
implementation("org.slf4j:slf4j-api:2.0.13")
implementation("ch.qos.logback:logback-classic:1.5.6")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
}
application { mainClass = "com.example.App" }
tasks.test { useJUnitPlatform() }$ ./gradlew build # 编译 + 测试 + 打包
$ ./gradlew test
$ ./gradlew run # 通过 application 插件直接跑
$ ./gradlew dependenciesJUnit 5:单元测试
Java 标准测试框架。约定:测试类放在 src/test/java,类名以 Test 结尾,方法加 @Test。assertEquals 等断言来自 org.junit.jupiter.api.Assertions。Maven / Gradle 的 surefire 插件自动发现并跑。
// src/main/java/com/example/MathUtil.java
package com.example;
public class MathUtil {
public static int add(int a, int b) { return a + b; }
public static int divide(int a, int b) {
if (b == 0) throw new IllegalArgumentException("b=0");
return a / b;
}
}// src/test/java/com/example/MathUtilTest.java
package com.example;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.*;
class MathUtilTest {
@BeforeEach
void setUp() { /* 每个测试前都跑一次 */ }
@Test
@DisplayName("add: 普通正数")
void addPositive() {
assertEquals(5, MathUtil.add(2, 3));
}
@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5",
"-1, 1, 0"
})
void addTable(int a, int b, int expected) {
assertEquals(expected, MathUtil.add(a, b));
}
@Test
void divideByZeroThrows() {
IllegalArgumentException e = assertThrows(
IllegalArgumentException.class,
() -> MathUtil.divide(1, 0)
);
assertEquals("b=0", e.getMessage());
}
}SLF4J + Logback:标准日志
应用场景:所有生产代码都要打结构化日志。SLF4J 是日志门面(API),Logback 是具体实现(绑定)。约定:`private static final Logger log = LoggerFactory.getLogger(XX.class);`,**不要再写 System.out**。
// src/main/java/com/example/Service.java
package com.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Service {
private static final Logger log = LoggerFactory.getLogger(Service.class);
public void handle(long userId) {
log.info("start handle user_id={}", userId); // {} 占位符,惰性求值
try {
doWork(userId);
} catch (Exception e) {
log.error("handle failed user_id={}", userId, e); // 最后一个参数自动当 exception
}
}
private void doWork(long id) {
log.debug("working on {}", id);
if (id < 0) throw new IllegalArgumentException("bad id");
}
}Logback 配置文件 src/main/resources/logback.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
<logger name="com.example" level="DEBUG"/>
</configuration>打包与运行
应用场景:交付一个可运行的 fat jar 或 docker 镜像。Maven 的 maven-shade-plugin / Gradle 的 shadow 插件能把依赖一起打进 jar,java -jar 直接跑。Spring Boot 自带 spring-boot-maven-plugin。
# Maven 打 jar
$ mvn clean package
$ java -jar target/myapp-1.0.0.jar
# Spring Boot fat jar 是默认就 self-runnable 的
$ java -jar target/myapp.jar --server.port=8081
# 注入运行时参数
$ java -Xmx512m -Dspring.profiles.active=prod -jar app.jar
# 交叉构建 docker(Spring Boot 3 内置 buildpacks)
$ mvn spring-boot:build-image
$ docker run -p 8080:8080 myapp:1.0.0Java 版本选择(LTS 策略)
Java 每 6 个月一个新版本,每 2 年一个 LTS(长期支持,更新 8 年以上)。生产建议**只用 LTS**:Java 8 / 11 / 17 / 21。新项目今天直接选 17 或 21;Java 8 仅在维护老系统时用。
- Java 8(2014,LTS):lambda、Stream、Optional、新日期 API。占有率仍高。
- Java 11(2018,LTS):var、HTTP Client、单文件源运行、移除 JavaFX。Spring 5 / Spring Boot 2 起点。
- Java 17(2021,LTS):record、sealed、pattern matching、text blocks。Spring Boot 3+ 强制最低。**本教程基线**。
- Java 21(2023,LTS):virtual threads(Loom)、sequenced collections、模式匹配增强。新项目优选。
Java 模块系统(Java 9+,了解即可)
模块系统给 JDK 自身做了拆分(java.base / java.sql / java.xml…)。应用层模块化(写 module-info.java)应用很少——绝大多数后端项目用 Maven / Gradle 划分子项目就够了。这里只需要知道它存在,常见错误信息能看懂。
// src/main/java/module-info.java
module com.example.myapp {
requires java.sql; // 声明依赖的 JDK 模块
requires org.slf4j; // 第三方模块
exports com.example.api; // 哪些包对外可见
opens com.example.entity to hibernate.core; // 反射开放给特定模块
}工程实践要点
- 用 Maven 或 Gradle 管理依赖、跑测试、打包;别手动下 jar、别手动 javac
- 每个项目放 .editorconfig 和 .gitignore(target/、.idea/、*.class)
- CI(GitHub Actions / Jenkins)至少跑:mvn verify(含测试)+ 静态检查(SpotBugs/Checkstyle/SonarLint)
- 依赖管理:每个 dep 显式写版本,避免传递依赖冲突;用 mvn dependency:tree 排查
- 日志:永远用 SLF4J + 占位符,配 JSON 格式给 ELK / Loki
- 测试:表驱动 + ParameterizedTest 覆盖业务分支;JaCoCo 看覆盖率
- 代码规范:Google Java Style 或团队约定,工具自动化(Spotless / google-java-format)
- 新项目用 Java 17 LTS 起步;Spring Boot 3.x;JUnit 5