Skip to content

Java 生态系统笔记 ​

1. 构建工具 ​

1.1 Maven ​

Maven 是一个基于项目对象模型(POM)的构建工具,用于管理项目的依赖、构建、测试和部署。

核心概念:

  • POM:Project Object Model,项目配置文件
  • 坐标:groupId、artifactId、version
  • 仓库:中央仓库、私有仓库、本地仓库
  • 依赖管理:传递依赖、排除依赖
  • 生命周期:clean、compile、test、package、install、deploy
  • 插件:用于执行具体的构建任务

示例 POM 文件:

xml
<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>myapp</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <!-- 属性配置 -->
    <properties>
        <java.version>17</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot.version>3.2.0</spring-boot.version>
    </properties>
    
    <!-- 依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <!-- 依赖声明 -->
    <dependencies>
        <!-- Spring Boot 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        
        <!-- 数据库依赖 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <!-- 构建配置 -->
    <build>
        <plugins>
            <!-- Spring Boot Maven 插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            
            <!-- Maven 编译器插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            
            <!-- Maven 资源插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
        
        <!-- 资源过滤 -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    
    <!-- 仓库配置 -->
    <repositories>
        <!-- 中央仓库 -->
        <repository>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    
    <pluginRepositories>
        <pluginRepository>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>
<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>myapp</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <!-- 属性配置 -->
    <properties>
        <java.version>17</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot.version>3.2.0</spring-boot.version>
    </properties>
    
    <!-- 依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <!-- 依赖声明 -->
    <dependencies>
        <!-- Spring Boot 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        
        <!-- 数据库依赖 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <!-- 构建配置 -->
    <build>
        <plugins>
            <!-- Spring Boot Maven 插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            
            <!-- Maven 编译器插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            
            <!-- Maven 资源插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
        
        <!-- 资源过滤 -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    
    <!-- 仓库配置 -->
    <repositories>
        <!-- 中央仓库 -->
        <repository>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    
    <pluginRepositories>
        <pluginRepository>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>

常用 Maven 命令:

bash
# 清理目标目录
mvn clean

# 编译源代码
mvn compile

# 运行测试
mvn test

# 打包项目
mvn package

# 安装到本地仓库
mvn install

# 部署到远程仓库
mvn deploy

# 运行 Spring Boot 应用
mvn spring-boot:run

# 跳过测试编译和执行
mvn package -DskipTests
mvn package -Dmaven.test.skip=true

# 指定配置文件
mvn package -Pproduction
# 清理目标目录
mvn clean

# 编译源代码
mvn compile

# 运行测试
mvn test

# 打包项目
mvn package

# 安装到本地仓库
mvn install

# 部署到远程仓库
mvn deploy

# 运行 Spring Boot 应用
mvn spring-boot:run

# 跳过测试编译和执行
mvn package -DskipTests
mvn package -Dmaven.test.skip=true

# 指定配置文件
mvn package -Pproduction

1.2 Gradle ​

Gradle 是一个基于 Groovy 或 Kotlin 语言的构建工具,结合了 Maven 和 Ant 的优点,提供了更灵活的构建配置。

核心概念:

  • 项目:一个 Gradle 构建对应一个项目
  • 任务:构建过程中的一个操作
  • 插件:扩展 Gradle 功能
  • 依赖管理:支持 Maven 和 Ivy 仓库
  • 构建脚本:build.gradle(Groovy)或 build.gradle.kts(Kotlin)

示例 build.gradle 文件:

groovy
plugins {
    id 'org.springframework.boot' version '3.2.0'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'java'
    id 'war' // 如果是 Web 应用
}

group = 'com.example'
version = '1.0.0-SNAPSHOT'

// Java 配置
java {
    sourceCompatibility = '17'
    targetCompatibility = '17'
}

// 仓库配置
repositories {
    mavenCentral()
    // 本地仓库
    mavenLocal()
    // 自定义仓库
    maven {
        url = uri('https://repo.example.com/maven2')
        credentials {
            username = project.findProperty('repoUsername') ?: System.getenv('REPO_USERNAME')
            password = project.findProperty('repoPassword') ?: System.getenv('REPO_PASSWORD')
        }
    }
}

// 依赖配置
dependencies {
    // Spring Boot 依赖
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    
    // 数据库依赖
    runtimeOnly 'com.mysql:mysql-connector-j'
    
    // 测试依赖
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.junit.jupiter:junit-jupiter-api'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

// 测试配置
tasks.named('test') {
    useJUnitPlatform()
}

// 打包配置
tasks.named('bootJar') {
    archiveFileName = "${project.name}-${project.version}.jar"
}

// 自定义任务
task hello {
    doLast {
        println 'Hello from Gradle!'
    }
}
plugins {
    id 'org.springframework.boot' version '3.2.0'
    id 'io.spring.dependency-management' version '1.1.4'
    id 'java'
    id 'war' // 如果是 Web 应用
}

group = 'com.example'
version = '1.0.0-SNAPSHOT'

// Java 配置
java {
    sourceCompatibility = '17'
    targetCompatibility = '17'
}

// 仓库配置
repositories {
    mavenCentral()
    // 本地仓库
    mavenLocal()
    // 自定义仓库
    maven {
        url = uri('https://repo.example.com/maven2')
        credentials {
            username = project.findProperty('repoUsername') ?: System.getenv('REPO_USERNAME')
            password = project.findProperty('repoPassword') ?: System.getenv('REPO_PASSWORD')
        }
    }
}

// 依赖配置
dependencies {
    // Spring Boot 依赖
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    
    // 数据库依赖
    runtimeOnly 'com.mysql:mysql-connector-j'
    
    // 测试依赖
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.junit.jupiter:junit-jupiter-api'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

// 测试配置
tasks.named('test') {
    useJUnitPlatform()
}

// 打包配置
tasks.named('bootJar') {
    archiveFileName = "${project.name}-${project.version}.jar"
}

// 自定义任务
task hello {
    doLast {
        println 'Hello from Gradle!'
    }
}

常用 Gradle 命令:

bash
# 清理构建目录
./gradlew clean

# 编译源代码
./gradlew compileJava

# 运行测试
./gradlew test

# 打包项目
./gradlew build

# 安装到本地仓库
./gradlew publishToMavenLocal

# 运行 Spring Boot 应用
./gradlew bootRun

# 跳过测试
./gradlew build -x test

# 查看任务列表
./gradlew tasks

# 查看依赖树
./gradlew dependencies
# 清理构建目录
./gradlew clean

# 编译源代码
./gradlew compileJava

# 运行测试
./gradlew test

# 打包项目
./gradlew build

# 安装到本地仓库
./gradlew publishToMavenLocal

# 运行 Spring Boot 应用
./gradlew bootRun

# 跳过测试
./gradlew build -x test

# 查看任务列表
./gradlew tasks

# 查看依赖树
./gradlew dependencies

2. 测试框架 ​

2.1 JUnit 5 ​

JUnit 5 是 Java 单元测试的标准框架,于 2017 年发布,分为三个模块:

  • JUnit Platform:测试执行引擎
  • JUnit Jupiter:测试 API 和扩展模型
  • JUnit Vintage:向后兼容 JUnit 3 和 JUnit 4

示例:

java
import org.junit.jupiter.api.*;

// 测试类
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // 每个类创建一个实例
@DisplayName("User Service Tests") // 测试类名称
public class UserServiceTest {
    
    private UserService userService;
    
    // 在所有测试方法之前执行
    @BeforeAll
    static void beforeAll() {
        System.out.println("Before all tests");
    }
    
    // 在每个测试方法之前执行
    @BeforeEach
    void setUp() {
        userService = new UserServiceImpl(new InMemoryUserRepository());
        System.out.println("Before each test");
    }
    
    // 测试方法
    @Test
    @DisplayName("Test create user") // 测试方法名称
    void testCreateUser() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        
        // 执行操作
        User createdUser = userService.createUser(user);
        
        // 断言
        Assertions.assertNotNull(createdUser);
        Assertions.assertEquals("John", createdUser.getFirstName());
        Assertions.assertEquals("Doe", createdUser.getLastName());
        Assertions.assertEquals("john.doe@example.com", createdUser.getEmail());
    }
    
    @Test
    @DisplayName("Test get user by id")
    void testGetUserById() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User createdUser = userService.createUser(user);
        
        // 执行操作
        User foundUser = userService.getUserById(createdUser.getId());
        
        // 断言
        Assertions.assertNotNull(foundUser);
        Assertions.assertEquals(createdUser.getId(), foundUser.getId());
    }
    
    @Test
    @DisplayName("Test delete user")
    void testDeleteUser() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User createdUser = userService.createUser(user);
        
        // 执行操作
        userService.deleteUser(createdUser.getId());
        
        // 断言:预期抛出异常
        Assertions.assertThrows(UserNotFoundException.class, () -> {
            userService.getUserById(createdUser.getId());
        });
    }
    
    // 参数化测试
    @ParameterizedTest
    @DisplayName("Test with parameters")
    @ValueSource(strings = {"John", "Jane", "Bob"}) // 参数源
    void testWithParameters(String firstName) {
        User user = new User(firstName, "Doe", firstName.toLowerCase() + ".doe@example.com");
        User createdUser = userService.createUser(user);
        Assertions.assertEquals(firstName, createdUser.getFirstName());
    }
    
    // 禁用测试
    @Test
    @Disabled("This test is disabled for now")
    void disabledTest() {
        // 测试内容
    }
    
    // 在每个测试方法之后执行
    @AfterEach
    void tearDown() {
        System.out.println("After each test");
    }
    
    // 在所有测试方法之后执行
    @AfterAll
    static void afterAll() {
        System.out.println("After all tests");
    }
}
import org.junit.jupiter.api.*;

// 测试类
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // 每个类创建一个实例
@DisplayName("User Service Tests") // 测试类名称
public class UserServiceTest {
    
    private UserService userService;
    
    // 在所有测试方法之前执行
    @BeforeAll
    static void beforeAll() {
        System.out.println("Before all tests");
    }
    
    // 在每个测试方法之前执行
    @BeforeEach
    void setUp() {
        userService = new UserServiceImpl(new InMemoryUserRepository());
        System.out.println("Before each test");
    }
    
    // 测试方法
    @Test
    @DisplayName("Test create user") // 测试方法名称
    void testCreateUser() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        
        // 执行操作
        User createdUser = userService.createUser(user);
        
        // 断言
        Assertions.assertNotNull(createdUser);
        Assertions.assertEquals("John", createdUser.getFirstName());
        Assertions.assertEquals("Doe", createdUser.getLastName());
        Assertions.assertEquals("john.doe@example.com", createdUser.getEmail());
    }
    
    @Test
    @DisplayName("Test get user by id")
    void testGetUserById() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User createdUser = userService.createUser(user);
        
        // 执行操作
        User foundUser = userService.getUserById(createdUser.getId());
        
        // 断言
        Assertions.assertNotNull(foundUser);
        Assertions.assertEquals(createdUser.getId(), foundUser.getId());
    }
    
    @Test
    @DisplayName("Test delete user")
    void testDeleteUser() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User createdUser = userService.createUser(user);
        
        // 执行操作
        userService.deleteUser(createdUser.getId());
        
        // 断言:预期抛出异常
        Assertions.assertThrows(UserNotFoundException.class, () -> {
            userService.getUserById(createdUser.getId());
        });
    }
    
    // 参数化测试
    @ParameterizedTest
    @DisplayName("Test with parameters")
    @ValueSource(strings = {"John", "Jane", "Bob"}) // 参数源
    void testWithParameters(String firstName) {
        User user = new User(firstName, "Doe", firstName.toLowerCase() + ".doe@example.com");
        User createdUser = userService.createUser(user);
        Assertions.assertEquals(firstName, createdUser.getFirstName());
    }
    
    // 禁用测试
    @Test
    @Disabled("This test is disabled for now")
    void disabledTest() {
        // 测试内容
    }
    
    // 在每个测试方法之后执行
    @AfterEach
    void tearDown() {
        System.out.println("After each test");
    }
    
    // 在所有测试方法之后执行
    @AfterAll
    static void afterAll() {
        System.out.println("After all tests");
    }
}

2.2 Mockito ​

Mockito 是一个流行的 Java 测试框架,用于创建和配置模拟对象,简化单元测试。

示例:

java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.*;

// 使用 Mockito 扩展
@ExtendWith(MockitoExtension.class)
public class UserServiceMockitoTest {
    
    // 模拟 UserRepository
    @Mock
    private UserRepository userRepository;
    
    // 将模拟对象注入到 UserService 中
    @InjectMocks
    private UserServiceImpl userService;
    
    @Test
    void testGetUserById() {
        // 准备数据
        Long userId = 1L;
        User mockUser = new User("John", "Doe", "john.doe@example.com");
        mockUser.setId(userId);
        
        // 配置模拟对象的行为
        when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser));
        
        // 执行操作
        User foundUser = userService.getUserById(userId);
        
        // 断言
        Assertions.assertNotNull(foundUser);
        Assertions.assertEquals(userId, foundUser.getId());
        Assertions.assertEquals("John", foundUser.getFirstName());
        
        // 验证模拟对象的方法是否被调用
        verify(userRepository, times(1)).findById(userId);
        verifyNoMoreInteractions(userRepository);
    }
    
    @Test
    void testCreateUser() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User mockUser = new User("John", "Doe", "john.doe@example.com");
        mockUser.setId(1L);
        
        // 配置模拟对象
        when(userRepository.save(user)).thenReturn(mockUser);
        
        // 执行操作
        User createdUser = userService.createUser(user);
        
        // 断言
        Assertions.assertNotNull(createdUser);
        Assertions.assertEquals(1L, createdUser.getId());
        
        // 验证
        verify(userRepository, times(1)).save(user);
    }
    
    @Test
    void testDeleteUser() {
        // 准备数据
        Long userId = 1L;
        User mockUser = new User("John", "Doe", "john.doe@example.com");
        mockUser.setId(userId);
        
        // 配置模拟对象
        when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser));
        doNothing().when(userRepository).delete(mockUser);
        
        // 执行操作
        userService.deleteUser(userId);
        
        // 验证
        verify(userRepository, times(1)).findById(userId);
        verify(userRepository, times(1)).delete(mockUser);
    }
}
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.*;

// 使用 Mockito 扩展
@ExtendWith(MockitoExtension.class)
public class UserServiceMockitoTest {
    
    // 模拟 UserRepository
    @Mock
    private UserRepository userRepository;
    
    // 将模拟对象注入到 UserService 中
    @InjectMocks
    private UserServiceImpl userService;
    
    @Test
    void testGetUserById() {
        // 准备数据
        Long userId = 1L;
        User mockUser = new User("John", "Doe", "john.doe@example.com");
        mockUser.setId(userId);
        
        // 配置模拟对象的行为
        when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser));
        
        // 执行操作
        User foundUser = userService.getUserById(userId);
        
        // 断言
        Assertions.assertNotNull(foundUser);
        Assertions.assertEquals(userId, foundUser.getId());
        Assertions.assertEquals("John", foundUser.getFirstName());
        
        // 验证模拟对象的方法是否被调用
        verify(userRepository, times(1)).findById(userId);
        verifyNoMoreInteractions(userRepository);
    }
    
    @Test
    void testCreateUser() {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User mockUser = new User("John", "Doe", "john.doe@example.com");
        mockUser.setId(1L);
        
        // 配置模拟对象
        when(userRepository.save(user)).thenReturn(mockUser);
        
        // 执行操作
        User createdUser = userService.createUser(user);
        
        // 断言
        Assertions.assertNotNull(createdUser);
        Assertions.assertEquals(1L, createdUser.getId());
        
        // 验证
        verify(userRepository, times(1)).save(user);
    }
    
    @Test
    void testDeleteUser() {
        // 准备数据
        Long userId = 1L;
        User mockUser = new User("John", "Doe", "john.doe@example.com");
        mockUser.setId(userId);
        
        // 配置模拟对象
        when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser));
        doNothing().when(userRepository).delete(mockUser);
        
        // 执行操作
        userService.deleteUser(userId);
        
        // 验证
        verify(userRepository, times(1)).findById(userId);
        verify(userRepository, times(1)).delete(mockUser);
    }
}

2.3 Spring Boot Test ​

Spring Boot Test 提供了用于测试 Spring Boot 应用的工具和注解。

示例:

java
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

// 启动 Spring Boot 应用上下文
@SpringBootTest
// 自动配置 MockMvc
@AutoConfigureMockMvc
public class UserControllerTest {
    
    // 注入 MockMvc
    @Autowired
    private MockMvc mockMvc;
    
    // 模拟 UserService
    @MockBean
    private UserService userService;
    
    @Test
    void testGetUserById() throws Exception {
        // 准备数据
        Long userId = 1L;
        User user = new User("John", "Doe", "john.doe@example.com");
        user.setId(userId);
        
        // 配置模拟对象
        when(userService.getUserById(userId)).thenReturn(user);
        
        // 执行 HTTP 请求
        mockMvc.perform(get("/api/users/{id}", userId))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.id").value(userId))
            .andExpect(jsonPath("$.firstName").value("John"))
            .andExpect(jsonPath("$.lastName").value("Doe"))
            .andExpect(jsonPath("$.email").value("john.doe@example.com"));
        
        // 验证
        verify(userService, times(1)).getUserById(userId);
    }
    
    @Test
    void testCreateUser() throws Exception {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User createdUser = new User("John", "Doe", "john.doe@example.com");
        createdUser.setId(1L);
        
        // 配置模拟对象
        when(userService.createUser(any(User.class))).thenReturn(createdUser);
        
        // 执行 HTTP 请求
        mockMvc.perform(post("/api/users")
                .contentType("application/json")
                .content("{\"firstName\":\"John\",\"lastName\":\"Doe\",\"email\":\"john.doe@example.com\"}"))
            .andExpect(status().isCreated())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.id").value(1L))
            .andExpect(jsonPath("$.firstName").value("John"));
        
        // 验证
        verify(userService, times(1)).createUser(any(User.class));
    }
}
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

// 启动 Spring Boot 应用上下文
@SpringBootTest
// 自动配置 MockMvc
@AutoConfigureMockMvc
public class UserControllerTest {
    
    // 注入 MockMvc
    @Autowired
    private MockMvc mockMvc;
    
    // 模拟 UserService
    @MockBean
    private UserService userService;
    
    @Test
    void testGetUserById() throws Exception {
        // 准备数据
        Long userId = 1L;
        User user = new User("John", "Doe", "john.doe@example.com");
        user.setId(userId);
        
        // 配置模拟对象
        when(userService.getUserById(userId)).thenReturn(user);
        
        // 执行 HTTP 请求
        mockMvc.perform(get("/api/users/{id}", userId))
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.id").value(userId))
            .andExpect(jsonPath("$.firstName").value("John"))
            .andExpect(jsonPath("$.lastName").value("Doe"))
            .andExpect(jsonPath("$.email").value("john.doe@example.com"));
        
        // 验证
        verify(userService, times(1)).getUserById(userId);
    }
    
    @Test
    void testCreateUser() throws Exception {
        // 准备数据
        User user = new User("John", "Doe", "john.doe@example.com");
        User createdUser = new User("John", "Doe", "john.doe@example.com");
        createdUser.setId(1L);
        
        // 配置模拟对象
        when(userService.createUser(any(User.class))).thenReturn(createdUser);
        
        // 执行 HTTP 请求
        mockMvc.perform(post("/api/users")
                .contentType("application/json")
                .content("{\"firstName\":\"John\",\"lastName\":\"Doe\",\"email\":\"john.doe@example.com\"}"))
            .andExpect(status().isCreated())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.id").value(1L))
            .andExpect(jsonPath("$.firstName").value("John"));
        
        // 验证
        verify(userService, times(1)).createUser(any(User.class));
    }
}

3. 代码质量工具 ​

3.1 SonarQube ​

SonarQube 是一个开源的代码质量管理平台,用于检测代码中的 bugs、漏洞和代码异味。

主要功能:

  • 代码质量分析
  • 安全漏洞检测
  • 代码覆盖率报告
  • 持续集成支持
  • 多种语言支持

使用方法:

  1. 安装 SonarQube 服务器
  2. 在项目中添加 SonarQube Maven 或 Gradle 插件
  3. 运行分析命令
  4. 在 SonarQube 界面查看报告

Maven 配置:

xml
<plugin>
    <groupId>org.sonarsource.scanner.maven</groupId>
    <artifactId>sonar-maven-plugin</artifactId>
    <version>3.10.0.2594</version>
</plugin>
<plugin>
    <groupId>org.sonarsource.scanner.maven</groupId>
    <artifactId>sonar-maven-plugin</artifactId>
    <version>3.10.0.2594</version>
</plugin>

运行分析:

bash
# Maven
mvn sonar:sonar -Dsonar.projectKey=myapp -Dsonar.host.url=http://localhost:9000 -Dsonar.login=my-token

# Gradle
./gradlew sonar -Dsonar.projectKey=myapp -Dsonar.host.url=http://localhost:9000 -Dsonar.login=my-token
# Maven
mvn sonar:sonar -Dsonar.projectKey=myapp -Dsonar.host.url=http://localhost:9000 -Dsonar.login=my-token

# Gradle
./gradlew sonar -Dsonar.projectKey=myapp -Dsonar.host.url=http://localhost:9000 -Dsonar.login=my-token

3.2 Checkstyle ​

Checkstyle 是一个开发工具,用于检查 Java 代码是否符合编码标准。

主要功能:

  • 检查命名约定
  • 检查代码格式
  • 检查代码复杂度
  • 支持自定义规则
  • 与 IDE 集成

Maven 配置:

xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>3.3.0</version>
    <configuration>
        <configLocation>checkstyle.xml</configLocation>
        <failOnViolation>true</failOnViolation>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>3.3.0</version>
    <configuration>
        <configLocation>checkstyle.xml</configLocation>
        <failOnViolation>true</failOnViolation>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

运行检查:

bash
# Maven
mvn checkstyle:check

# Gradle
./gradlew checkstyleMain checkstyleTest
# Maven
mvn checkstyle:check

# Gradle
./gradlew checkstyleMain checkstyleTest

3.3 PMD ​

PMD 是一个源代码分析器,用于检测代码中的问题,如未使用的变量、空的 catch 块等。

主要功能:

  • 代码异味检测
  • 重复代码检测
  • 安全漏洞检测
  • 支持多种语言

Maven 配置:

xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.20.0</version>
    <configuration>
        <rulesets>
            <ruleset>rulesets/java/quickstart.xml</ruleset>
        </rulesets>
        <failOnViolation>true</failOnViolation>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.20.0</version>
    <configuration>
        <rulesets>
            <ruleset>rulesets/java/quickstart.xml</ruleset>
        </rulesets>
        <failOnViolation>true</failOnViolation>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

运行检查:

bash
# Maven
mvn pmd:check

# Gradle
./gradlew pmdMain pmdTest
# Maven
mvn pmd:check

# Gradle
./gradlew pmdMain pmdTest

4. 部署工具 ​

4.1 Docker ​

Docker 是一个开源的容器化平台,用于打包、分发和运行应用程序。

Dockerfile 示例:

dockerfile
# 使用官方 OpenJDK 17 镜像作为基础镜像
FROM openjdk:17-jdk-alpine

# 设置工作目录
WORKDIR /app

# 复制打包好的 JAR 文件到容器中
COPY target/myapp-1.0.0.jar app.jar

# 暴露端口
EXPOSE 8080

# 运行应用
ENTRYPOINT ["java", "-jar", "app.jar"]
# 使用官方 OpenJDK 17 镜像作为基础镜像
FROM openjdk:17-jdk-alpine

# 设置工作目录
WORKDIR /app

# 复制打包好的 JAR 文件到容器中
COPY target/myapp-1.0.0.jar app.jar

# 暴露端口
EXPOSE 8080

# 运行应用
ENTRYPOINT ["java", "-jar", "app.jar"]

Docker Compose 示例:

yaml
version: '3.8'

services:
  # 应用服务
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/mydb
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=password
    depends_on:
      - db
    restart: always
    networks:
      - my-network

  # 数据库服务
  db:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=mydb
      - MYSQL_CHARSET=utf8mb4
      - MYSQL_COLLATION=utf8mb4_unicode_ci
    volumes:
      - mysql-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: always
    networks:
      - my-network

# 网络配置
networks:
  my-network:
    driver: bridge

# 数据卷配置
volumes:
  mysql-data:
    driver: local
version: '3.8'

services:
  # 应用服务
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/mydb
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=password
    depends_on:
      - db
    restart: always
    networks:
      - my-network

  # 数据库服务
  db:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=mydb
      - MYSQL_CHARSET=utf8mb4
      - MYSQL_COLLATION=utf8mb4_unicode_ci
    volumes:
      - mysql-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: always
    networks:
      - my-network

# 网络配置
networks:
  my-network:
    driver: bridge

# 数据卷配置
volumes:
  mysql-data:
    driver: local

常用 Docker 命令:

bash
# 构建镜像
docker build -t myapp:1.0.0 .

# 运行容器
docker run -d -p 8080:8080 --name myapp-container myapp:1.0.0

# 查看容器日志
docker logs -f myapp-container

# 进入容器
docker exec -it myapp-container /bin/sh

# 停止容器
docker stop myapp-container

# 删除容器
docker rm myapp-container

# 查看镜像
docker images

# 删除镜像
docker rmi myapp:1.0.0

# 使用 Docker Compose 启动服务
docker-compose up -d

# 停止 Docker Compose 服务
docker-compose down

# 查看 Docker Compose 日志
docker-compose logs -f
# 构建镜像
docker build -t myapp:1.0.0 .

# 运行容器
docker run -d -p 8080:8080 --name myapp-container myapp:1.0.0

# 查看容器日志
docker logs -f myapp-container

# 进入容器
docker exec -it myapp-container /bin/sh

# 停止容器
docker stop myapp-container

# 删除容器
docker rm myapp-container

# 查看镜像
docker images

# 删除镜像
docker rmi myapp:1.0.0

# 使用 Docker Compose 启动服务
docker-compose up -d

# 停止 Docker Compose 服务
docker-compose down

# 查看 Docker Compose 日志
docker-compose logs -f

4.2 Kubernetes ​

Kubernetes 是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。

核心概念:

  • Pod:最小的部署单元,包含一个或多个容器
  • Deployment:管理 Pod 的部署和更新
  • Service:暴露 Pod 给其他服务或外部访问
  • Ingress:管理外部访问
  • ConfigMap:存储配置数据
  • Secret:存储敏感数据
  • Volume:持久化存储
  • Namespace:资源隔离

Deployment 示例:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  namespace: default
  labels:
    app: myapp
spec:
  replicas: 3 # 副本数量
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "prod"
        - name: SPRING_DATASOURCE_URL
          value: "jdbc:mysql://mysql-service:3306/mydb"
        - name: SPRING_DATASOURCE_USERNAME
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: username
        - name: SPRING_DATASOURCE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1"
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  namespace: default
  labels:
    app: myapp
spec:
  replicas: 3 # 副本数量
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "prod"
        - name: SPRING_DATASOURCE_URL
          value: "jdbc:mysql://mysql-service:3306/mydb"
        - name: SPRING_DATASOURCE_USERNAME
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: username
        - name: SPRING_DATASOURCE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1"

Service 示例:

yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: default
spec:
  selector:
    app: myapp
  type: LoadBalancer # 暴露服务给外部
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: default
spec:
  selector:
    app: myapp
  type: LoadBalancer # 暴露服务给外部
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

Ingress 示例:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-service
            port:
              number: 80
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp-service
            port:
              number: 80

ConfigMap 示例:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
  namespace: default
data:
  application.properties: |
    spring.application.name=myapp
    spring.profiles.active=prod
    logging.level.root=INFO
    logging.level.com.example=DEBUG
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
  namespace: default
data:
  application.properties: |
    spring.application.name=myapp
    spring.profiles.active=prod
    logging.level.root=INFO
    logging.level.com.example=DEBUG

Secret 示例:

yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: default
type: Opaque
data:
  username: cm9vdA== # base64 编码的 "root"
  password: cGFzc3dvcmQ= # base64 编码的 "password"
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: default
type: Opaque
data:
  username: cm9vdA== # base64 编码的 "root"
  password: cGFzc3dvcmQ= # base64 编码的 "password"

常用 Kubernetes 命令:

bash
# 查看所有 Pod
kubectl get pods -n default

# 查看 Deployment
kubectl get deployments -n default

# 查看 Service
kubectl get services -n default

# 查看 Ingress
kubectl get ingress -n default

# 查看 ConfigMap
kubectl get configmaps -n default

# 查看 Secret
kubectl get secrets -n default

# 应用配置
kubectl apply -f deployment.yaml

# 删除资源
kubectl delete -f deployment.yaml

# 查看 Pod 日志
kubectl logs -f myapp-deployment-xxx

# 进入 Pod
kubectl exec -it myapp-deployment-xxx -- /bin/sh

# 查看 Pod 描述
kubectl describe pod myapp-deployment-xxx

# 扩容 Deployment
kubectl scale deployment myapp-deployment --replicas=5

# 查看节点
kubectl get nodes

# 查看集群信息
kubectl cluster-info
# 查看所有 Pod
kubectl get pods -n default

# 查看 Deployment
kubectl get deployments -n default

# 查看 Service
kubectl get services -n default

# 查看 Ingress
kubectl get ingress -n default

# 查看 ConfigMap
kubectl get configmaps -n default

# 查看 Secret
kubectl get secrets -n default

# 应用配置
kubectl apply -f deployment.yaml

# 删除资源
kubectl delete -f deployment.yaml

# 查看 Pod 日志
kubectl logs -f myapp-deployment-xxx

# 进入 Pod
kubectl exec -it myapp-deployment-xxx -- /bin/sh

# 查看 Pod 描述
kubectl describe pod myapp-deployment-xxx

# 扩容 Deployment
kubectl scale deployment myapp-deployment --replicas=5

# 查看节点
kubectl get nodes

# 查看集群信息
kubectl cluster-info

5. 监控和日志 ​

5.1 Spring Boot Actuator ​

Spring Boot Actuator 提供了生产就绪的特性,用于监控和管理 Spring Boot 应用。

添加依赖:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置:

properties
# 暴露所有端点
management.endpoints.web.exposure.include=*

# 暴露的健康检查详情
management.endpoint.health.show-details=always

# 配置健康检查路径
management.endpoints.web.base-path=/actuator

# 配置 Prometheus 端点
management.endpoint.prometheus.enabled=true
# 暴露所有端点
management.endpoints.web.exposure.include=*

# 暴露的健康检查详情
management.endpoint.health.show-details=always

# 配置健康检查路径
management.endpoints.web.base-path=/actuator

# 配置 Prometheus 端点
management.endpoint.prometheus.enabled=true

常用端点:

  • /actuator/health - 健康检查
  • /actuator/info - 应用信息
  • /actuator/metrics - 指标信息
  • /actuator/prometheus - Prometheus 格式的指标
  • /actuator/env - 环境变量
  • /actuator/configprops - 配置属性
  • /actuator/loggers - 日志配置
  • /actuator/threaddump - 线程转储
  • /actuator/heapdump - 堆转储

5.2 Prometheus 和 Grafana ​

Prometheus 是一个开源的监控系统,用于收集和存储指标数据。 Grafana 是一个开源的可视化平台,用于展示 Prometheus 收集的数据。

Docker Compose 配置:

yaml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    restart: always

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin123
    restart: always
    depends_on:
      - prometheus

volumes:
  prometheus-data:
  grafana-data:
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    restart: always

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin123
    restart: always
    depends_on:
      - prometheus

volumes:
  prometheus-data:
  grafana-data:

Prometheus 配置文件:

yaml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

scrape_configs:
  - job_name: 'spring-actuator'
    metrics_path: '/actuator/prometheus'
    scrape_interval: 5s
    static_configs:
      - targets: ['host.docker.internal:8080']  # 应用地址
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

scrape_configs:
  - job_name: 'spring-actuator'
    metrics_path: '/actuator/prometheus'
    scrape_interval: 5s
    static_configs:
      - targets: ['host.docker.internal:8080']  # 应用地址

5.3 ELK Stack ​

ELK Stack 是 Elasticsearch、Logstash 和 Kibana 的组合,用于日志收集、存储和分析。

Docker Compose 配置:

yaml
version: '3.8'

services:
  # Elasticsearch 服务
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.8.0
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
      - ELASTIC_PASSWORD=password
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=false
    volumes:
      - es-data:/usr/share/elasticsearch/data
    restart: always

  # Logstash 服务
  logstash:
    image: docker.elastic.co/logstash/logstash:8.8.0
    ports:
      - "5044:5044"
      - "9600:9600"
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    environment:
      - LS_JAVA_OPTS=-Xms256m -Xmx256m
    depends_on:
      - elasticsearch
    restart: always

  # Kibana 服务
  kibana:
    image: docker.elastic.co/kibana/kibana:8.8.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=elastic
      - ELASTICSEARCH_PASSWORD=password
    depends_on:
      - elasticsearch
    restart: always

  # Filebeat 服务(可选,用于收集日志)
  filebeat:
    image: docker.elastic.co/beats/filebeat:8.8.0
    volumes:
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    depends_on:
      - logstash
    restart: always

volumes:
  es-data:
    driver: local
version: '3.8'

services:
  # Elasticsearch 服务
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.8.0
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
      - ELASTIC_PASSWORD=password
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=false
    volumes:
      - es-data:/usr/share/elasticsearch/data
    restart: always

  # Logstash 服务
  logstash:
    image: docker.elastic.co/logstash/logstash:8.8.0
    ports:
      - "5044:5044"
      - "9600:9600"
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    environment:
      - LS_JAVA_OPTS=-Xms256m -Xmx256m
    depends_on:
      - elasticsearch
    restart: always

  # Kibana 服务
  kibana:
    image: docker.elastic.co/kibana/kibana:8.8.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=elastic
      - ELASTICSEARCH_PASSWORD=password
    depends_on:
      - elasticsearch
    restart: always

  # Filebeat 服务(可选,用于收集日志)
  filebeat:
    image: docker.elastic.co/beats/filebeat:8.8.0
    volumes:
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    depends_on:
      - logstash
    restart: always

volumes:
  es-data:
    driver: local

6. 开发工具 ​

6.1 IDE ​

IntelliJ IDEA:

  • 功能强大的 Java IDE
  • 支持 Spring Boot、Maven、Gradle 等
  • 内置代码检查和重构工具
  • 支持 Docker 和 Kubernetes
  • 强大的调试功能

Eclipse:

  • 开源的 Java IDE
  • 支持多种插件
  • 适合大型项目
  • 支持团队协作

VS Code:

  • 轻量级的代码编辑器
  • 支持 Java 插件
  • 跨平台
  • 支持多种语言

6.2 其他工具 ​

Postman:用于测试 API Swagger/OpenAPI:用于 API 文档生成 Lombok:简化 Java 代码,减少样板代码 MapStruct:用于对象映射 DBeaver:数据库管理工具 Git:版本控制工具

7. 总结 ​

Java 生态系统非常丰富,提供了从开发到部署的全方位支持。本文涵盖了:

  1. 构建工具:Maven 和 Gradle,用于管理依赖和构建项目
  2. 测试框架:JUnit 5、Mockito 和 Spring Boot Test,用于编写和执行测试
  3. 代码质量工具:SonarQube、Checkstyle 和 PMD,用于保证代码质量
  4. 部署工具:Docker 和 Kubernetes,用于容器化和编排
  5. 监控和日志:Spring Boot Actuator、Prometheus、Grafana 和 ELK Stack,用于监控和日志管理
  6. 开发工具:IDE 和其他辅助工具,用于提高开发效率

掌握这些工具和技术,将有助于开发高质量、可维护的 Java 应用程序。随着技术的不断发展,Java 生态系统也在不断演进,开发者需要持续学习,跟上最新的技术趋势。