Java 开发指南
环境准备
Java 版本要求
推荐使用 Java 17 LTS 或更高版本以获得最新的语言特性和性能优化。
# 检查当前 Java 版本
java -version
javac -version
# 推荐使用 SDKMAN 管理 Java 版本
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
# 安装和使用 Java 17
sdk install java 17.0.8-tem
sdk use java 17.0.8-tem
sdk default java 17.0.8-tem
构建工具配置
Maven 配置
推荐的 pom.xml 配置:
<?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>java-project</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>
<!-- 依赖版本 -->
<spring.boot.version>3.2.0</spring.boot.version>
<junit.version>5.10.0</junit.version>
<mockito.version>5.5.0</mockito.version>
<slf4j.version>2.0.9</slf4j.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 Starter -->
<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-validation</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>
Gradle 配置
推荐的 build.gradle 配置:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
id 'com.diffplug.spotless' version '6.22.0'
}
group = 'com.example'
version = '1.0.0'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
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-validation'
implementation 'org.springframework.boot:spring-boot-starter-security'
// 数据库
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'
// 工具库
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// 测试
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
jvmArgs '--enable-preview'
}
tasks.named('compileJava') {
options.compilerArgs += '--enable-preview'
}
// 代码格式化
spotless {
java {
googleJavaFormat('1.17.0')
removeUnusedImports()
trimTrailingWhitespace()
endWithNewline()
}
}
开发工具和扩展
在 Kiro 中推荐安装以下扩展:
核心扩展
Java 开发必备:
- Extension Pack for Java: Java 开发工具包
- Spring Boot Extension Pack: Spring 开发支持
- Maven for Java: Maven 项目管理
- Gradle for Java: Gradle 构建支持
代码质量:
- SonarLint: 代码质量检查
- Checkstyle: 代码风格检查
- SpotBugs: 静态代码分析
- Error Prone: Google 错误检测
测试工具:
- Java Test Runner: 测试执行
- Coverage Gutters: 代码覆盖率显示
- JUnit Test Explorer: JUnit 测试管理
现代 Java 特性应用
Java 17+ 新特性
Record Classes
// 使用 Record 简化数据类
public record User(Long id, String name, String email, LocalDateTime createdAt) {
// 自定义构造器
public User {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("Name cannot be null or blank");
}
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("Invalid email format");
}
}
// 自定义方法
public String getDisplayName() {
return name.toUpperCase();
}
// 静态工厂方法
public static User createNew(String name, String email) {
return new User(null, name, email, LocalDateTime.now());
}
}
// 在 Spring Boot 中使用
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {
User user = User.createNew(request.name(), request.email());
// 保存用户逻辑
return ResponseEntity.ok(user);
}
}
public record CreateUserRequest(String name, String email) {}
Sealed Classes
// 密封类用于限制继承层次
public sealed class PaymentMethod
permits CreditCard, BankTransfer, DigitalWallet {
public abstract String getPaymentType();
public abstract boolean isSecure();
}
public final class CreditCard extends PaymentMethod {
private final String cardNumber;
private final String expiryDate;
public CreditCard(String cardNumber, String expiryDate) {
this.cardNumber = cardNumber;
this.expiryDate = expiryDate;
}
@Override
public String getPaymentType() {
return "CREDIT_CARD";
}
@Override
public boolean isSecure() {
return true;
}
}
public final class BankTransfer extends PaymentMethod {
private final String accountNumber;
private final String routingNumber;
public BankTransfer(String accountNumber, String routingNumber) {
this.accountNumber = accountNumber;
this.routingNumber = routingNumber;
}
@Override
public String getPaymentType() {
return "BANK_TRANSFER";
}
@Override
public boolean isSecure() {
return true;
}
}
public final class DigitalWallet extends PaymentMethod {
private final String walletId;
private final String provider;
public DigitalWallet(String walletId, String provider) {
this.walletId = walletId;
this.provider = provider;
}
@Override
public String getPaymentType() {
return "DIGITAL_WALLET";
}
@Override
public boolean isSecure() {
return "TRUSTED_PROVIDER".equals(provider);
}
}
// 使用 switch 表达式处理密封类
public class PaymentProcessor {
public String processPayment(PaymentMethod method, double amount) {
return switch (method) {
case CreditCard cc -> processCreditCard(cc, amount);
case BankTransfer bt -> processBankTransfer(bt, amount);
case DigitalWallet dw -> processDigitalWallet(dw, amount);
};
}
private String processCreditCard(CreditCard card, double amount) {
return "Processing $%.2f via credit card".formatted(amount);
}
private String processBankTransfer(BankTransfer transfer, double amount) {
return "Processing $%.2f via bank transfer".formatted(amount);
}
private String processDigitalWallet(DigitalWallet wallet, double amount) {
return "Processing $%.2f via digital wallet".formatted(amount);
}
}
Pattern Matching
// 增强的 instanceof
public class ShapeProcessor {
public double calculateArea(Object shape) {
if (shape instanceof Rectangle rect) {
return rect.width() * rect.height();
} else if (shape instanceof Circle circle) {
return Math.PI * circle.radius() * circle.radius();
} else if (shape instanceof Triangle triangle) {
double s = (triangle.a() + triangle.b() + triangle.c()) / 2;
return Math.sqrt(s * (s - triangle.a()) * (s - triangle.b()) * (s - triangle.c()));
}
throw new IllegalArgumentException("Unknown shape: " + shape);
}
// 使用 switch 表达式的模式匹配
public String getShapeDescription(Object shape) {
return switch (shape) {
case Rectangle rect -> "Rectangle: %.1f x %.1f".formatted(rect.width(), rect.height());
case Circle circle -> "Circle: radius %.1f".formatted(circle.radius());
case Triangle triangle -> "Triangle: sides %.1f, %.1f, %.1f"
.formatted(triangle.a(), triangle.b(), triangle.c());
case null -> "No shape provided";
default -> "Unknown shape: " + shape.getClass().getSimpleName();
};
}
}
public record Rectangle(double width, double height) {}
public record Circle(double radius) {}
public record Triangle(double a, double b, double c) {}
Text Blocks
public class SqlQueryBuilder {
public static final String COMPLEX_QUERY = """
SELECT u.id, u.name, u.email, p.title, p.content, p.created_at
FROM users u
INNER JOIN posts p ON u.id = p.user_id
WHERE u.active = true
AND p.published = true
AND p.created_at >= ?
ORDER BY p.created_at DESC
LIMIT ?
""";
public static final String JSON_TEMPLATE = """
{
"user": {
"id": %d,
"name": "%s",
"email": "%s"
},
"preferences": {
"theme": "dark",
"notifications": true
}
}
""";
public String generateUserJson(Long id, String name, String email) {
return JSON_TEMPLATE.formatted(id, name, email);
}
}
Spring Boot 应用开发
项目结构最佳实践
src/
├── main/
│ ├── java/
│ │ └── com/example/myapp/
│ │ ├── MyAppApplication.java
│ │ ├── config/
│ │ │ ├── SecurityConfig.java
│ │ │ ├── DatabaseConfig.java
│ │ │ └── CacheConfig.java
│ │ ├── controller/
│ │ │ ├── UserController.java
│ │ │ ├── ProductController.java
│ │ │ └── advice/
│ │ │ └── GlobalExceptionHandler.java
│ │ ├── service/
│ │ │ ├── UserService.java
│ │ │ ├── ProductService.java
│ │ │ └── impl/
│ │ │ ├── UserServiceImpl.java
│ │ │ └── ProductServiceImpl.java
│ │ ├── repository/
│ │ │ ├── UserRepository.java
│ │ │ └── ProductRepository.java
│ │ ├── model/
│ │ │ ├── entity/
│ │ │ │ ├── User.java
│ │ │ │ └── Product.java
│ │ │ ├── dto/
│ │ │ │ ├── UserDto.java
│ │ │ │ └── ProductDto.java
│ │ │ └── request/
│ │ │ ├── CreateUserRequest.java
│ │ │ └── UpdateUserRequest.java
│ │ ├── exception/
│ │ │ ├── UserNotFoundException.java
│ │ │ └── BusinessException.java
│ │ └── util/
│ │ ├── DateUtils.java
│ │ └── ValidationUtils.java
│ └── resources/
│ ├── application.yml
│ ├── application-dev.yml
│ ├── application-prod.yml
│ └── db/migration/
│ └── V1__Initial_schema.sql
└── test/
└── java/
└── com/example/myapp/
├── controller/
├── service/
├── repository/
└── integration/
Spring Boot 配置
application.yml 配置
spring:
application:
name: my-java-app
profiles:
active: dev
datasource:
url: jdbc:postgresql://localhost:5432/myapp
username: ${DB_USERNAME:postgres}
password: ${DB_PASSWORD:password}
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
jpa:
hibernate:
ddl-auto: validate
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
use_sql_comments: true
jdbc:
batch_size: 25
order_inserts: true
order_updates: true
cache:
type: redis
redis:
time-to-live: 3600s
data:
redis:
host: localhost
port: 6379
timeout: 2s
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
server:
port: 8080
servlet:
context-path: /api
compression:
enabled: true
mime-types: application/json,application/xml,text/html,text/xml,text/plain
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: when_authorized
metrics:
export:
prometheus:
enabled: true
logging:
level:
com.example.myapp: INFO
org.springframework.security: DEBUG
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/application.log
max-size: 10MB
max-history: 30
实体和 Repository 设计
实体类设计
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", unique = true, nullable = false, length = 50)
private String username;
@Column(name = "email", unique = true, nullable = false, length = 100)
@Email
private String email;
@Column(name = "password", nullable = false)
private String password;
@Column(name = "first_name", length = 50)
private String firstName;
@Column(name = "last_name", length = 50)
private String lastName;
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
private UserStatus status;
@CreationTimestamp
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Version
private Long version;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Post> posts = new ArrayList<>();
// 自定义方法
public String getFullName() {
return String.format("%s %s", firstName, lastName).trim();
}
public boolean isActive() {
return UserStatus.ACTIVE.equals(status);
}
}
public enum UserStatus {
ACTIVE,
INACTIVE,
SUSPENDED,
DELETED
}
Repository 接口
@Repository
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
List<User> findByStatus(UserStatus status);
Page<User> findByStatusAndCreatedAtAfter(UserStatus status, LocalDateTime createdAt, Pageable pageable);
@Query("SELECT u FROM User u WHERE u.firstName LIKE %:name% OR u.lastName LIKE %:name%")
List<User> findByNameContaining(@Param("name") String name);
@Query(value = "SELECT * FROM users WHERE created_at > :date AND status = :status", nativeQuery = true)
List<User> findRecentActiveUsers(@Param("date") LocalDateTime date, @Param("status") String status);
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.id IN :ids")
void updateUserStatus(@Param("ids") List<Long> ids, @Param("status") UserStatus status);
// 使用 Specification 进行动态查询
static Specification<User> hasStatus(UserStatus status) {
return (root, query, cb) -> cb.equal(root.get("status"), status);
}
static Specification<User> createdAfter(LocalDateTime date) {
return (root, query, cb) -> cb.greaterThan(root.get("createdAt"), date);
}
static Specification<User> nameContains(String name) {
return (root, query, cb) -> {
if (name == null || name.trim().isEmpty()) {
return cb.conjunction();
}
String pattern = "%" + name.toLowerCase() + "%";
return cb.or(
cb.like(cb.lower(root.get("firstName")), pattern),
cb.like(cb.lower(root.get("lastName")), pattern)
);
};
}
}
Service 层设计
@Service
@Transactional(readOnly = true)
@Slf4j
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final UserMapper userMapper;
private final ApplicationEventPublisher eventPublisher;
public UserServiceImpl(UserRepository userRepository,
PasswordEncoder passwordEncoder,
UserMapper userMapper,
ApplicationEventPublisher eventPublisher) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.userMapper = userMapper;
this.eventPublisher = eventPublisher;
}
@Override
@Transactional
public UserDto createUser(CreateUserRequest request) {
log.info("Creating new user with username: {}", request.username());
// 验证用户名和邮箱唯一性
validateUserUniqueness(request.username(), request.email());
// 创建用户实体
User user = User.builder()
.username(request.username())
.email(request.email())
.password(passwordEncoder.encode(request.password()))
.firstName(request.firstName())
.lastName(request.lastName())
.status(UserStatus.ACTIVE)
.build();
// 保存用户
User savedUser = userRepository.save(user);
// 发布用户创建事件
eventPublisher.publishEvent(new UserCreatedEvent(savedUser.getId()));
log.info("User created successfully with ID: {}", savedUser.getId());
return userMapper.toDto(savedUser);
}
@Override
public Optional<UserDto> findByUsername(String username) {
return userRepository.findByUsername(username)
.map(userMapper::toDto);
}
@Override
public Page<UserDto> findUsers(UserSearchCriteria criteria, Pageable pageable) {
Specification<User> spec = buildSpecification(criteria);
Page<User> users = userRepository.findAll(spec, pageable);
return users.map(userMapper::toDto);
}
@Override
@Transactional
public UserDto updateUser(Long userId, UpdateUserRequest request) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("User not found with ID: " + userId));
// 更新用户信息
updateUserFields(user, request);
User updatedUser = userRepository.save(user);
log.info("User updated successfully: {}", userId);
return userMapper.toDto(updatedUser);
}
@Override
@Transactional
public void deleteUser(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("User not found with ID: " + userId));
user.setStatus(UserStatus.DELETED);
userRepository.save(user);
eventPublisher.publishEvent(new UserDeletedEvent(userId));
log.info("User marked as deleted: {}", userId);
}
private void validateUserUniqueness(String username, String email) {
if (userRepository.findByUsername(username).isPresent()) {
throw new BusinessException("Username already exists: " + username);
}
if (userRepository.findByEmail(email).isPresent()) {
throw new BusinessException("Email already exists: " + email);
}
}
private Specification<User> buildSpecification(UserSearchCriteria criteria) {
return Specification.where(UserRepository.hasStatus(criteria.status()))
.and(UserRepository.nameContains(criteria.name()))
.and(UserRepository.createdAfter(criteria.createdAfter()));
}
private void updateUserFields(User user, UpdateUserRequest request) {
if (request.firstName() != null) {
user.setFirstName(request.firstName());
}
if (request.lastName() != null) {
user.setLastName(request.lastName());
}
if (request.email() != null && !request.email().equals(user.getEmail())) {
if (userRepository.findByEmail(request.email()).isPresent()) {
throw new BusinessException("Email already exists: " + request.email());
}
user.setEmail(request.email());
}
}
}
// 事件类
public record UserCreatedEvent(Long userId) {}
public record UserDeletedEvent(Long userId) {}
// 搜索条件
public record UserSearchCriteria(
UserStatus status,
String name,
LocalDateTime createdAfter
) {}
控制器设计
@RestController
@RequestMapping("/users")
@Validated
@Slf4j
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<ApiResponse<UserDto>> createUser(
@Valid @RequestBody CreateUserRequest request) {
UserDto user = userService.createUser(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success("User created successfully", user));
}
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<UserDto>> getUser(@PathVariable Long id) {
UserDto user = userService.findById(id)
.orElseThrow(() -> new UserNotFoundException("User not found with ID: " + id));
return ResponseEntity.ok(ApiResponse.success(user));
}
@GetMapping
public ResponseEntity<ApiResponse<Page<UserDto>>> getUsers(
@RequestParam(required = false) UserStatus status,
@RequestParam(required = false) String name,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime createdAfter,
@PageableDefault(size = 20, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) {
UserSearchCriteria criteria = new UserSearchCriteria(status, name, createdAfter);
Page<UserDto> users = userService.findUsers(criteria, pageable);
return ResponseEntity.ok(ApiResponse.success(users));
}
@PutMapping("/{id}")
public ResponseEntity<ApiResponse<UserDto>> updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
UserDto user = userService.updateUser(id, request);
return ResponseEntity.ok(ApiResponse.success("User updated successfully", user));
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
// 通用 API 响应格式
public record ApiResponse<T>(
boolean success,
String message,
T data,
LocalDateTime timestamp
) {
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, "Success", data, LocalDateTime.now());
}
public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>(true, message, data, LocalDateTime.now());
}
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(false, message, null, LocalDateTime.now());
}
}
Kiro 核心功能应用
智能代码分析
Kiro 可以分析 Java 代码并提供优化建议:
// Kiro 会建议的代码改进示例
// 原始代码 - 存在性能和可读性问题
public class OrderProcessor {
public List<Order> processOrders(List<Order> orders) {
List<Order> result = new ArrayList<>();
for (Order order : orders) {
if (order.getStatus().equals("PENDING")) {
order.setStatus("PROCESSING");
calculateTotal(order);
validateOrder(order);
if (order.isValid()) {
result.add(order);
}
}
}
return result;
}
private void calculateTotal(Order order) {
double total = 0;
for (OrderItem item : order.getItems()) {
total += item.getPrice() * item.getQuantity();
}
order.setTotal(total);
}
}
// Kiro 建议的改进版本
@Service
@Slf4j
public class OrderProcessor {
private final OrderValidator orderValidator;
private final OrderCalculationService calculationService;
public OrderProcessor(OrderValidator orderValidator,
OrderCalculationService calculationService) {
this.orderValidator = orderValidator;
this.calculationService = calculationService;
}
public List<Order> processOrders(List<Order> orders) {
if (orders == null || orders.isEmpty()) {
return Collections.emptyList();
}
return orders.parallelStream()
.filter(order -> OrderStatus.PENDING.equals(order.getStatus()))
.peek(order -> order.setStatus(OrderStatus.PROCESSING))
.peek(calculationService::calculateTotal)
.filter(orderValidator::validateOrder)
.collect(Collectors.toList());
}
}
@Component
public class OrderCalculationService {
public void calculateTotal(Order order) {
BigDecimal total = order.getItems().stream()
.map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
order.setTotal(total);
}
}
// 使用枚举替代字符串常量
public enum OrderStatus {
PENDING,
PROCESSING,
COMPLETED,
CANCELLED
}
代理钩子配置
配置针对 Java 项目的自动化钩子:
Maven 项目管理钩子
name: "Maven 依赖检查"
trigger: onSave
filePattern: "pom.xml"
instructions: |
检查 Maven 项目的依赖和配置:
1. 运行 `mvn dependency:analyze` 检查未使用的依赖
2. 运行 `mvn versions:display-dependency-updates` 检查依赖更新
3. 检查安全漏洞 `mvn org.owasp:dependency-check-maven:check`
4. 验证 Java 版本兼容性
5. 提供优化建议和安全更新计划
代码质量检查钩子
name: "Java 代码质量检查"
trigger: onSave
filePattern: "src/**/*.java"
instructions: |
执行全面的 Java 代码质量检查:
1. 运行 Checkstyle 检查代码风格
2. 使用 SpotBugs 进行静态代码分析
3. 运行 PMD 检查代码质量
4. 检查单元测试覆盖率
5. 验证 Javadoc 文档完整性
6. 提供具体的改进建议
Spring Boot 配置检查钩子
name: "Spring Boot 配置验证"
trigger: onSave
filePattern: "src/main/resources/application*.yml"
instructions: |
验证 Spring Boot 配置:
1. 检查配置属性的正确性
2. 验证数据库连接配置
3. 检查安全配置最佳实践
4. 验证生产环境配置
5. 提供性能优化建议
测试生成钩子
name: "JUnit 测试生成器"
trigger: onSave
filePattern: "src/main/java/**/*.java"
instructions: |
为新的或修改的 Java 类生成 JUnit 测试:
1. 分析类的公共方法和业务逻辑
2. 生成基本的单元测试用例
3. 包含边界条件和异常情况测试
4. 添加模拟对象测试(使用 Mockito)
5. 确保测试覆盖主要代码路径
6. 遵循 AAA 模式(Arrange, Act, Assert)
测试策略
JUnit 5 测试配置
// 基础测试类配置
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private UserMapper userMapper;
@Mock
private ApplicationEventPublisher eventPublisher;
@InjectMocks
private UserServiceImpl userService;
@Test
@DisplayName("应该成功创建新用户")
void shouldCreateUserSuccessfully() {
// Given
CreateUserRequest request = new CreateUserRequest(
"testuser", "test@example.com", "password123", "John", "Doe"
);
User user = User.builder()
.id(1L)
.username("testuser")
.email("test@example.com")
.build();
UserDto expectedDto = new UserDto(1L, "testuser", "test@example.com", "John", "Doe");
when(userRepository.findByUsername("testuser")).thenReturn(Optional.empty());
when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.empty());
when(passwordEncoder.encode("password123")).thenReturn("encodedPassword");
when(userRepository.save(any(User.class))).thenReturn(user);
when(userMapper.toDto(user)).thenReturn(expectedDto);
// When
UserDto result = userService.createUser(request);
// Then
assertThat(result).isNotNull();
assertThat(result.username()).isEqualTo("testuser");
assertThat(result.email()).isEqualTo("test@example.com");
verify(userRepository).save(any(User.class));
verify(eventPublisher).publishEvent(any(UserCreatedEvent.class));
}
@Test
@DisplayName("用户名重复时应该抛出异常")
void shouldThrowExceptionWhenUsernameExists() {
// Given
CreateUserRequest request = new CreateUserRequest(
"existinguser", "test@example.com", "password123", "John", "Doe"
);
when(userRepository.findByUsername("existinguser"))
.thenReturn(Optional.of(new User()));
// When & Then
assertThatThrownBy(() -> userService.createUser(request))
.isInstanceOf(BusinessException.class)
.hasMessageContaining("Username already exists");
verify(userRepository, never()).save(any(User.class));
}
@ParameterizedTest
@ValueSource(strings = {"", " ", "a", "ab"})
@DisplayName("用户名长度不足时应该失败")
void shouldFailWithInvalidUsernameLength(String username) {
CreateUserRequest request = new CreateUserRequest(
username, "test@example.com", "password123", "John", "Doe"
);
assertThatThrownBy(() -> userService.createUser(request))
.isInstanceOf(ValidationException.class);
}
}
集成测试
@SpringBootTest
@Testcontainers
@Transactional
class UserControllerIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private UserRepository userRepository;
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Test
@DisplayName("POST /users 应该创建新用户")
void shouldCreateNewUser() {
// Given
CreateUserRequest request = new CreateUserRequest(
"newuser", "new@example.com", "password123", "New", "User"
);
// When
ResponseEntity<ApiResponse> response = restTemplate.postForEntity(
"/users", request, ApiResponse.class
);
// Then
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(response.getBody().success()).isTrue();
Optional<User> savedUser = userRepository.findByUsername("newuser");
assertThat(savedUser).isPresent();
assertThat(savedUser.get().getEmail()).isEqualTo("new@example.com");
}
@Test
@DisplayName("GET /users 应该返回分页的用户列表")
void shouldReturnPagedUsers() {
// Given
createTestUsers();
// When
ResponseEntity<String> response = restTemplate.getForEntity(
"/users?size=10&page=0", String.class
);
// Then
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
// 进一步的 JSON 解析和验证
}
private void createTestUsers() {
for (int i = 1; i <= 15; i++) {
User user = User.builder()
.username("user" + i)
.email("user" + i + "@example.com")
.firstName("User")
.lastName(String.valueOf(i))
.status(UserStatus.ACTIVE)
.build();
userRepository.save(user);
}
}
}
性能优化
JVM 调优
# 生产环境 JVM 参数推荐
java -XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:G1HeapRegionSize=16m \
-XX:+UseStringDeduplication \
-XX:+OptimizeStringConcat \
-XX:+UseCompressedOops \
-Xms2g \
-Xmx4g \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/heapdump.hprof \
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-Xloggc:/var/log/gc.log \
-jar myapp.jar
数据库优化
// 批量操作优化
@Repository
public class OptimizedUserRepository {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void batchInsertUsers(List<User> users) {
int batchSize = 25;
for (int i = 0; i < users.size(); i++) {
entityManager.persist(users.get(i));
if (i % batchSize == 0 && i > 0) {
entityManager.flush();
entityManager.clear();
}
}
entityManager.flush();
entityManager.clear();
}
// 使用投影优化查询
@Query("SELECT new com.example.dto.UserSummary(u.id, u.username, u.email) " +
"FROM User u WHERE u.status = :status")
List<UserSummary> findUserSummariesByStatus(@Param("status") UserStatus status);
}
// DTO 投影
public record UserSummary(Long id, String username, String email) {}
缓存策略
@Service
@CacheConfig(cacheNames = "users")
public class CachedUserService {
@Cacheable(key = "#id")
public UserDto findById(Long id) {
// 数据库查询逻辑
}
@Cacheable(key = "#username")
public UserDto findByUsername(String username) {
// 数据库查询逻辑
}
@CacheEvict(key = "#user.id")
public UserDto updateUser(UserDto user) {
// 更新逻辑
}
@CacheEvict(allEntries = true)
public void clearAllCache() {
// 清除所有缓存
}
}
// Redis 配置
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}
推荐资源
官方文档
工具和框架
构建工具:
- Maven: 项目管理和构建
- Gradle: 现代构建工具
- SBT: Scala/Java 构建工具
开发框架:
- Spring Boot: 企业级应用框架
- Quarkus: 云原生 Java 框架
- Micronaut: 微服务框架
测试框架:
- JUnit 5: 单元测试框架
- Mockito: 模拟框架
- Testcontainers: 集成测试
- WireMock: API 模拟
代码质量:
- Checkstyle: 代码风格检查
- SpotBugs: 静态代码分析
- SonarQube: 代码质量平台
- JaCoCo: 代码覆盖率
性能监控
- APM 工具:New Relic、AppDynamics、Datadog
- JVM 监控:JVisualVM、JProfiler、Async Profiler
- 日志分析:ELK Stack、Splunk、Fluentd
页面最后更新:2025年7月21日