Spring Boot 中使用 Lombok 進行依賴注入的示例
下面我將展示 Spring Boot 中使用 Lombok 進行依賴注入的不同方式,包括構造器注入、屬性注入和 setter 方法注入,以及相應的測試用例。
1. 構造器注入(推薦方式)
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;@Service
@RequiredArgsConstructor
public class UserService {private final UserRepository userRepository;private final PasswordEncoder passwordEncoder;// Lombok 會自動生成包含所有 final 字段的構造器// 相當于:// public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {// this.userRepository = userRepository;// this.passwordEncoder = passwordEncoder;// }
}
2. 屬性注入(不推薦,僅作演示)
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OrderService {@Autowired@Setterprivate PaymentService paymentService;@Autowired@Setterprivate InventoryService inventoryService;
}
3. Setter 方法注入
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class ProductService {private ProductRepository productRepository;private DiscountService discountService;@Autowiredpublic void setProductRepository(ProductRepository productRepository) {this.productRepository = productRepository;}@Autowired@Setter // 也可以使用 Lombok 的 @Setter 注解public void setDiscountService(DiscountService discountService) {this.discountService = discountService;}
}
4. 測試用例示例
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;@ExtendWith(MockitoExtension.class)
public class UserServiceTest {@Mockprivate UserRepository userRepository;@Mockprivate PasswordEncoder passwordEncoder;@InjectMocksprivate UserService userService;@Testpublic void testCreateUser() {// 準備測試數據String username = "testUser";String password = "password123";String encodedPassword = "encodedPassword123";// 定義 mock 行為when(passwordEncoder.encode(password)).thenReturn(encodedPassword);when(userRepository.save(any(User.class))).thenAnswer(invocation -> invocation.getArgument(0));// 執行測試User result = userService.createUser(username, password);// 驗證結果assertNotNull(result);assertEquals(username, result.getUsername());assertEquals(encodedPassword, result.getPassword());// 驗證交互verify(passwordEncoder).encode(password);verify(userRepository).save(any(User.class));}
}
5. 綜合示例(使用 Lombok 和 Spring)
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Controller;@Controller
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class UserController {private final UserService userService;private final AuditService auditService;@PostMappingpublic ResponseEntity<User> createUser(@RequestBody UserDto userDto) {User user = userService.createUser(userDto);auditService.logUserCreation(user);return ResponseEntity.ok(user);}
}
springboot 測試代碼中使用構造方法
@SpringBootTest
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Test1RepositoryTest {protected final CcProcessRepository ccProcessRepository;
其他參考: lombok.config,lombok1.8.30 測試類未生效,只生成了 @ConstructorProperties
# 阻止配置向上冒泡
#config.stopBubbling = true
# 全局同時配置兩種注解(需要Lombok 1.18.16+)
# 為所有生成的構造器自動添加 @ConstructorProperties
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Autowired
lombok.anyConstructor.addConstructorProperties = true
#lombok.copyableAnnotations += org.springframework.context.annotation.Lazy
注意事項
-
推薦使用構造器注入(使用
@RequiredArgsConstructor
),因為:- 明確依賴關系
- 方便測試
- 不可變(final)字段
- 符合單一職責原則
-
屬性注入雖然簡潔,但有以下缺點:
- 隱藏依賴關系
- 難以測試
- 可能導致循環依賴
-
在測試中,使用
@Mock
創建 mock 對象,使用@InjectMocks
讓 Mockito 自動注入這些 mock 到被測試對象中。 -
確保項目中已正確配置 Lombok 插件(IDE 和構建工具都需要)。