SpringBoot測試之@SpringBootTest與MockMvc的實戰(zhàn)應(yīng)用小結(jié)
引言
在現(xiàn)代企業(yè)級應(yīng)用開發(fā)中,測試已成為確保軟件質(zhì)量的關(guān)鍵環(huán)節(jié)。SpringBoot作為當前最流行的Java開發(fā)框架,提供了完善的測試支持機制。本文將深入探討SpringBoot測試中兩個核心工具:@SpringBootTest注解與MockMvc測試框架的實戰(zhàn)應(yīng)用,幫助開發(fā)者構(gòu)建更穩(wěn)健的測試體系,提高代碼質(zhì)量與可維護性。
一、SpringBoot測試基礎(chǔ)
1.1 測試環(huán)境配置
SpringBoot提供了豐富的測試支持,使開發(fā)者能夠方便地進行單元測試和集成測試。在SpringBoot項目中進行測試需要引入spring-boot-starter-test依賴,該依賴包含JUnit、Spring Test、AssertJ等測試相關(guān)庫。測試環(huán)境的正確配置是高效測試的基礎(chǔ),確保測試用例能夠在與生產(chǎn)環(huán)境相似的條件下運行,從而提高測試結(jié)果的可靠性。
// build.gradle配置
dependencies {
// SpringBoot基礎(chǔ)依賴
implementation 'org.springframework.boot:spring-boot-starter-web'
// 測試相關(guān)依賴
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// JUnit 5支持
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
}
// 或者在Maven中的pom.xml配置
/*
<dependencies>
<!-- SpringBoot基礎(chǔ)依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 測試相關(guān)依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
*/1.2 測試目錄結(jié)構(gòu)
一個規(guī)范的測試目錄結(jié)構(gòu)有助于測試用例的組織和管理。在SpringBoot項目中,測試代碼通常位于src/test/java目錄下,測試資源文件位于src/test/resources目錄。測試類的包結(jié)構(gòu)應(yīng)與主代碼保持一致,便于關(guān)聯(lián)和維護。測試配置文件可以覆蓋主配置,為測試提供專用環(huán)境參數(shù)。
src
├── main
│ ├── java
│ │ └── com.example.demo
│ │ ├── controller
│ │ ├── service
│ │ └── repository
│ └── resources
│ └── application.properties
└── test
├── java
│ └── com.example.demo
│ ├── controller // 控制器測試類
│ ├── service // 服務(wù)測試類
│ └── repository // 數(shù)據(jù)訪問測試類
└── resources
└── application-test.properties // 測試專用配置二、@SpringBootTest注解詳解
2.1 基本用法與配置選項
@SpringBootTest注解是SpringBoot測試的核心,它提供了加載完整應(yīng)用程序上下文的能力。通過這個注解,可以創(chuàng)建接近真實環(huán)境的測試環(huán)境,使集成測試更加可靠。@SpringBootTest支持多種配置選項,可以根據(jù)測試需求進行靈活調(diào)整,包括指定啟動類、測試配置文件、Web環(huán)境類型等。
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import static org.junit.jupiter.api.Assertions.assertNotNull;
// 基本用法:加載完整的Spring應(yīng)用上下文
@SpringBootTest
public class BasicApplicationTests {
@Autowired
private Environment environment; // 注入環(huán)境變量
@Test
void contextLoads() {
// 驗證上下文是否正確加載
assertNotNull(environment);
System.out.println("Active profiles: " + String.join(", ", environment.getActiveProfiles()));
}
}
// 高級配置:自定義測試屬性
@SpringBootTest(
// 指定啟動類
classes = DemoApplication.class,
// 指定Web環(huán)境類型
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
// 設(shè)置測試屬性
properties = {
"spring.profiles.active=test",
"server.servlet.context-path=/api"
}
)
class CustomizedApplicationTest {
// 測試代碼...
}2.2 不同WebEnvironment模式的應(yīng)用場景
@SpringBootTest注解的webEnvironment屬性定義了測試的Web環(huán)境類型,有四種可選值:MOCK、RANDOM_PORT、DEFINED_PORT和NONE。每種模式適用于不同的測試場景。正確選擇Web環(huán)境模式可以提高測試效率,減少資源消耗。
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
// MOCK模式:不啟動服務(wù)器,適用于通過MockMvc測試控制器
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class MockWebEnvironmentTest {
// 使用MockMvc測試...
}
// RANDOM_PORT模式:啟動真實服務(wù)器,隨機端口,適用于端到端測試
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RandomPortWebEnvironmentTest {
@LocalServerPort
private int port; // 獲取隨機分配的端口
@Autowired
private TestRestTemplate restTemplate;
@Test
void testHomeEndpoint() {
// 發(fā)送真實HTTP請求
String response = restTemplate.getForObject(
"http://localhost:" + port + "/api/home",
String.class
);
assertThat(response).contains("Welcome");
}
}
// DEFINED_PORT模式:使用application.properties中定義的端口
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class DefinedPortWebEnvironmentTest {
// 使用固定端口測試...
}
// NONE模式:不啟動Web環(huán)境,適用于純業(yè)務(wù)邏輯測試
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class NoWebEnvironmentTest {
// 僅測試服務(wù)層和存儲層...
}三、MockMvc實戰(zhàn)應(yīng)用
3.1 MockMvc基本使用方法
MockMvc是Spring MVC測試框架的核心組件,它模擬HTTP請求和響應(yīng),無需啟動真實服務(wù)器即可測試控制器。MockMvc提供了流暢的API,可以構(gòu)建請求、執(zhí)行調(diào)用、驗證響應(yīng)。這種方式的測試執(zhí)行速度快,資源消耗少,特別適合控制器單元測試。使用MockMvc可以確保Web層代碼的正確性和穩(wěn)定性。
package com.example.demo.controller;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
// @WebMvcTest專注于測試控制器層,只加載MVC相關(guān)組件
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc; // MockMvc由Spring自動注入
@Test
void testGetUserById() throws Exception {
// 執(zhí)行GET請求并驗證響應(yīng)
mockMvc.perform(get("/users/1")) // 構(gòu)建GET請求
.andExpect(status().isOk()) // 驗證HTTP狀態(tài)碼為200
.andExpect(content().contentType("application/json")) // 驗證內(nèi)容類型
.andExpect(content().json("{\"id\":1,\"name\":\"John\"}")); // 驗證JSON響應(yīng)內(nèi)容
}
}3.2 高級請求構(gòu)建和響應(yīng)驗證
MockMvc提供了豐富的請求構(gòu)建選項和響應(yīng)驗證方法,可以全面測試控制器的各種行為。通過高級API,可以模擬復(fù)雜的請求場景,包括添加請求頭、設(shè)置參數(shù)、提交表單數(shù)據(jù)、上傳文件等。同時,MockMvc還提供了詳細的響應(yīng)驗證機制,可以檢查HTTP狀態(tài)碼、響應(yīng)頭、響應(yīng)體內(nèi)容等。
package com.example.demo.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(ProductController.class)
public class ProductControllerAdvancedTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper; // 用于JSON轉(zhuǎn)換
@Test
void testCreateProduct() throws Exception {
// 創(chuàng)建測試數(shù)據(jù)
Product product = new Product(null, "筆記本電腦", 6999.99, 10);
// 執(zhí)行POST請求
mockMvc.perform(
post("/products") // POST請求
.contentType(MediaType.APPLICATION_JSON) // 設(shè)置Content-Type
.header("Authorization", "Bearer token123") // 添加自定義請求頭
.content(objectMapper.writeValueAsString(product)) // 請求體JSON
)
.andDo(MockMvcResultHandlers.print()) // 打印請求和響應(yīng)詳情
.andExpect(status().isCreated()) // 期望返回201狀態(tài)碼
.andExpect(header().exists("Location")) // 驗證響應(yīng)頭包含Location
.andExpect(jsonPath("$.id", not(nullValue()))) // 驗證ID已生成
.andExpect(jsonPath("$.name", is("筆記本電腦"))) // 驗證屬性值
.andExpect(jsonPath("$.price", closeTo(6999.99, 0.01))); // 驗證浮點數(shù)
}
@Test
void testSearchProducts() throws Exception {
// 測試帶查詢參數(shù)的GET請求
mockMvc.perform(
get("/products/search")
.param("keyword", "電腦") // 添加查詢參數(shù)
.param("minPrice", "5000")
.param("maxPrice", "10000")
)
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(greaterThan(0)))) // 驗證數(shù)組不為空
.andExpect(jsonPath("$[0].name", containsString("電腦"))); // 驗證結(jié)果包含關(guān)鍵詞
}
}
// 簡單的產(chǎn)品類
class Product {
private Long id;
private String name;
private double price;
private int stock;
// 構(gòu)造函數(shù)、getter和setter略
public Product(Long id, String name, double price, int stock) {
this.id = id;
this.name = name;
this.price = price;
this.stock = stock;
}
// getter和setter略...
}四、模擬服務(wù)層與依賴
4.1 使用@MockBean模擬服務(wù)
在測試控制器時,通常需要模擬服務(wù)層的行為。Spring Boot提供了@MockBean注解,可以用來替換Spring容器中的bean為Mockito模擬對象。這種方式使得控制器測試可以專注于控制層邏輯,無需關(guān)心服務(wù)層的實際實現(xiàn)。通過配置模擬對象的返回值,可以測試控制器在不同場景下的行為。
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays;
import java.util.Optional;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(UserController.class)
public class UserControllerWithMockServiceTest {
@Autowired
private MockMvc mockMvc;
@MockBean // 創(chuàng)建并注入UserService的模擬實現(xiàn)
private UserService userService;
@Test
void testGetUserById() throws Exception {
// 配置模擬服務(wù)的行為
User mockUser = new User(1L, "張三", "zhangsan@example.com");
when(userService.findById(1L)).thenReturn(Optional.of(mockUser));
when(userService.findById(99L)).thenReturn(Optional.empty()); // 模擬用戶不存在的情況
// 測試成功場景
mockMvc.perform(get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.name").value("張三"));
// 測試用戶不存在的場景
mockMvc.perform(get("/users/99"))
.andExpect(status().isNotFound()); // 期望返回404
}
@Test
void testGetAllUsers() throws Exception {
// 配置模擬服務(wù)返回用戶列表
when(userService.findAll()).thenReturn(Arrays.asList(
new User(1L, "張三", "zhangsan@example.com"),
new User(2L, "李四", "lisi@example.com")
));
// 測試獲取所有用戶API
mockMvc.perform(get("/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$.length()").value(2))
.andExpect(jsonPath("$[0].name").value("張三"))
.andExpect(jsonPath("$[1].name").value("李四"));
}
}
// User模型類
class User {
private Long id;
private String name;
private String email;
// 構(gòu)造函數(shù)、getter和setter略
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// getter和setter略...
}4.2 測試異常處理和邊界情況
全面的測試應(yīng)該包括對異常情況和邊界條件的處理。在SpringBoot應(yīng)用中,控制器通常會通過@ExceptionHandler或@ControllerAdvice處理異常。通過MockMvc可以有效地測試這些異常處理機制,確保系統(tǒng)在異常情況下也能夠正確響應(yīng)。測試邊界情況可以提高代碼的健壯性。
package com.example.demo.controller;
import com.example.demo.exception.ResourceNotFoundException;
import com.example.demo.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(OrderController.class)
public class OrderControllerExceptionTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private OrderService orderService;
@Test
void testResourceNotFoundExceptionHandling() throws Exception {
// 配置模擬服務(wù)拋出異常
when(orderService.getOrderById(anyLong()))
.thenThrow(new ResourceNotFoundException("Order not found with id: 999"));
// 驗證異常是否被正確處理
mockMvc.perform(get("/orders/999"))
.andExpect(status().isNotFound()) // 期望返回404
.andExpect(jsonPath("$.message").value("Order not found with id: 999"))
.andExpect(jsonPath("$.timestamp").exists());
}
@Test
void testInvalidInputHandling() throws Exception {
// 測試無效輸入的處理
mockMvc.perform(
post("/orders")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"customerName\":\"\",\"amount\":-10}") // 無效數(shù)據(jù)
)
.andExpect(status().isBadRequest()) // 期望返回400
.andExpect(jsonPath("$.fieldErrors").isArray())
.andExpect(jsonPath("$.fieldErrors[?(@.field=='customerName')]").exists())
.andExpect(jsonPath("$.fieldErrors[?(@.field=='amount')]").exists());
}
@Test
void testUnauthorizedAccess() throws Exception {
// 測試未授權(quán)訪問的處理
doThrow(new SecurityException("Unauthorized access")).when(orderService)
.deleteOrder(anyLong());
mockMvc.perform(get("/orders/123/delete"))
.andExpect(status().isUnauthorized()) // 期望返回401
.andExpect(jsonPath("$.error").value("Unauthorized access"));
}
}五、測試最佳實踐
5.1 測試數(shù)據(jù)準備與清理
良好的測試應(yīng)當具有隔離性和可重復(fù)性。在SpringBoot測試中,應(yīng)當注意測試數(shù)據(jù)的準備和清理工作。使用@BeforeEach和@AfterEach注解可以在每個測試方法前后執(zhí)行準備和清理操作。對于數(shù)據(jù)庫測試,可以使用@Sql注解執(zhí)行SQL腳本,或者配合@Transactional注解自動回滾事務(wù)。
package com.example.demo.repository;
import com.example.demo.entity.Employee;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.jdbc.Sql;
import java.time.LocalDate;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest // 專用于JPA倉庫層測試的注解
public class EmployeeRepositoryTest {
@Autowired
private EmployeeRepository employeeRepository;
@BeforeEach
void setUp() {
// 測試前準備數(shù)據(jù)
employeeRepository.saveAll(List.of(
new Employee(null, "張三", "開發(fā)", 12000.0, LocalDate.of(2020, 5, 1)),
new Employee(null, "李四", "測試", 10000.0, LocalDate.of(2021, 3, 15)),
new Employee(null, "王五", "開發(fā)", 15000.0, LocalDate.of(2019, 8, 12))
));
}
@AfterEach
void tearDown() {
// 測試后清理數(shù)據(jù)
employeeRepository.deleteAll();
}
@Test
void testFindByDepartment() {
// 測試按部門查詢
List<Employee> developers = employeeRepository.findByDepartment("開發(fā)");
assertThat(developers).hasSize(2);
assertThat(developers).extracting(Employee::getName)
.containsExactlyInAnyOrder("張三", "王五");
}
@Test
@Sql("/test-data/additional-employees.sql") // 執(zhí)行SQL腳本添加更多測試數(shù)據(jù)
void testFindBySalaryRange() {
// 測試按薪資范圍查詢
List<Employee> employees = employeeRepository.findBySalaryBetween(11000.0, 14000.0);
assertThat(employees).hasSize(2);
assertThat(employees).extracting(Employee::getName)
.contains("張三");
}
}
// Employee實體類
class Employee {
private Long id;
private String name;
private String department;
private Double salary;
private LocalDate hireDate;
// 構(gòu)造函數(shù)、getter和setter略
public Employee(Long id, String name, String department, Double salary, LocalDate hireDate) {
this.id = id;
this.name = name;
this.department = department;
this.salary = salary;
this.hireDate = hireDate;
}
// getter略...
}5.2 測試覆蓋率與持續(xù)集成
測試覆蓋率是衡量測試質(zhì)量的重要指標,高覆蓋率通常意味著更少的未測試代碼和更少的潛在bug。在SpringBoot項目中,可以使用JaCoCo等工具統(tǒng)計測試覆蓋率。將測試集成到CI/CD流程中,確保每次代碼提交都會觸發(fā)自動測試,可以盡早發(fā)現(xiàn)問題,提高開發(fā)效率。
// 在build.gradle中配置JaCoCo測試覆蓋率插件
/*
plugins {
id 'jacoco'
}
jacoco {
toolVersion = "0.8.7"
}
test {
finalizedBy jacocoTestReport // 測試完成后生成覆蓋率報告
}
jacocoTestReport {
dependsOn test // 確保測試已執(zhí)行
reports {
xml.enabled true
html.enabled true
}
}
// 設(shè)置覆蓋率閾值
jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 0.80 // 最低80%覆蓋率
}
}
}
}
*/
// 示例測試類 - 確保高覆蓋率
package com.example.demo.service;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@SpringBootTest
public class TaxCalculatorServiceTest {
@Autowired
private TaxCalculatorService taxCalculatorService;
@ParameterizedTest
@CsvSource({
"5000.0, 0.0", // 不超過起征點
"8000.0, 90.0", // 第一檔稅率3%
"20000.0, 1590.0", // 第二檔稅率10%
"50000.0, 7590.0" // 第三檔稅率20%
})
void testCalculateIncomeTax(double income, double expectedTax) {
double tax = taxCalculatorService.calculateIncomeTax(income);
assertThat(tax).isEqualTo(expectedTax);
}
@Test
void testCalculateIncomeTaxWithNegativeIncome() {
// 測試邊界情況:負收入
assertThatThrownBy(() -> taxCalculatorService.calculateIncomeTax(-1000.0))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Income cannot be negative");
}
// 更多測試用例,確保高覆蓋率...
}總結(jié)
本文詳細介紹了SpringBoot測試環(huán)境中@SpringBootTest注解與MockMvc測試框架的實戰(zhàn)應(yīng)用。@SpringBootTest提供了加載完整應(yīng)用上下文的能力,支持不同的Web環(huán)境模式,適用于各種集成測試場景。MockMvc則專注于控制器層測試,通過模擬HTTP請求和響應(yīng),無需啟動真實服務(wù)器即可驗證控制器行為。在實際開發(fā)中,合理配置測試環(huán)境、準備測試數(shù)據(jù)、模擬服務(wù)依賴、處理異常和邊界情況,對于構(gòu)建健壯的測試體系至關(guān)重要。遵循最佳實踐,如保持測試隔離性、追求高測試覆蓋率、集成自動化測試流程等,能夠顯著提高代碼質(zhì)量和開發(fā)效率。通過本文介紹的技術(shù)和方法,開發(fā)者可以構(gòu)建更加可靠和高效的SpringBoot應(yīng)用測試體系,為項目的長期穩(wěn)定運行提供有力保障。
到此這篇關(guān)于SpringBoot測試之@SpringBootTest與MockMvc的實戰(zhàn)應(yīng)用小結(jié)的文章就介紹到這了,更多相關(guān)SpringBoot測試@SpringBootTest與MockMvc內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java LocalCache 本地緩存的實現(xiàn)實例
本篇文章主要介紹了Java LocalCache 本地緩存的實現(xiàn)實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-05-05
Spring解讀@Component和@Configuration的區(qū)別以及源碼分析
通過實例分析@Component和@Configuration注解的區(qū)別,核心在于@Configuration會通過CGLIB代理確保Bean的單例,而@Component不會,在Spring容器中,使用@Configuration注解的類會被CGLIB增強,保證了即使在同一個類中多次調(diào)用@Bean方法2024-10-10
SpringBoot下Mybatis的緩存的實現(xiàn)步驟
這篇文章主要介紹了SpringBoot下Mybatis的緩存的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04

