SpringBoot註解大全(詳細)

bug糕手發表於2024-09-25

1. @ActiveProfiles

用來宣告活動的profile–@ActiveProfiles(“prod”(這個prod定義在配置類中))

@RunWith(SpringRunner.class)  
@SpringBootTest  
@ActiveProfiles("test")  
public class MyApplicationTests {  
  
    @Test  
    public void contextLoads() {  
        // 你的測試程式碼  
    }  
}

@ActiveProfiles("test") 註解告訴 Spring框架啟用名為 test 的配置檔案。這意味著 Spring 將會載入與 test 配置檔案相關的所有 bean 和配置。如果你有多個配置檔案需要啟用,可以使用逗號分隔它們,如 @ActiveProfiles("test,test1")。

2. @After

後置建言(advice),標記那些在每個測試方法執行之後都會執行的程式碼,和@Before相反

import org.junit.After;  
import org.junit.Before;  
import org.junit.Test;  
  
public class MyTest {  
  
    @Before  
    public void setUp() {  
        // 在每個測試方法執行之前執行  
    }  
  
    @Test  
    public void testMethod1() {  
        // 測試方法1  
    }  
  
    @Test  
    public void testMethod2() {  
        // 測試方法2  
    }  
  
    @After  
    public void tearDown() {  
        // 在每個測試方法執行之後執行  
    }  
}

這個註解主要用於執行清理工作,比如釋放資源、恢復測試前的狀態等,以確保測試的獨立性和可重複性。

3. @Before

前置建言(advice),在原方法前執行。

4. @Around

環繞建言(advice),Spring AOP(面向切面程式設計)中的一個重要註解,環繞通知是一種在目標方法執行前後插入額外邏輯的增強處理,它可以在方法執行前進行操作,並在方法執行後進行操作,甚至能夠控制目標方法的執行與否、修改返回值或丟擲異常。

@Aspect  
public class LoggingAspect {  
  
    @Around("execution(* com.example.service.*.*(..))")  
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {  
        long startTime = System.currentTimeMillis();  
  
        // 在目標方法執行之前執行的邏輯  
        System.out.println("Method " + joinPoint.getSignature().getName() + " starts");  
  
        // 執行目標方法  
        Object proceed = joinPoint.proceed();  
  
        // 在目標方法執行之後執行的邏輯  
        long endTime = System.currentTimeMillis();  
        System.out.println("Method " + joinPoint.getSignature().getName() + " ends. Execution time: " + (endTime - startTime) + " ms");  
  
        return proceed;  
    }  
}

注意事項

  • 環繞通知中的 proceed() 方法必須被呼叫,否則目標方法將不會被執行。
  • 環繞通知需要謹慎使用,因為不當的使用可能會導致程式邏輯出錯或效能問題。
  • 確保環繞通知方法的返回型別與目標方法的返回型別一致,以便能夠正確返回結果。
  • 在環繞通知中處理異常時,要注意異常的傳遞和處理,避免程式異常終止。

5. @Aspect

Spring AOP(面向切面程式設計)中的一個核心註解,用於宣告一個類為切面(Aspect)

@Aspect 的主要作用:

  • 宣告切面:透過 @Aspect 註解,Spring 容器能夠識別出哪些類是切面類,進而對它們進行特殊的處理。
  • 定義通知:在切面類中,你可以定義各種通知(Advice),如前置通知(Before Advice)、後置通知(After Advice)、環繞通知(Around Advice)等,來指定在目標方法執行的不同階段需要執行的邏輯。
  • 指定切入點:透過切入點表示式(Pointcut Expression),你可以指定哪些類的哪些方法需要被增強(即哪些方法需要執行通知中定義的邏輯)。

使用 @Aspect 的基本步驟:

  1. 引入依賴:確保你的專案中已經引入了 Spring AOP 和 AspectJ 的相關依賴。

  2. 定義切面類:使用 @Aspect 註解來宣告一個類為切面類。

  3. 定義通知:在切面類中,使用 Spring AOP 提供的註解(如 @Before@After@Around 等)來定義通知。

  4. 指定切入點:在通知註解中,透過 valuepointcut 屬性來指定切入點表示式,以指定哪些方法需要被增強。

  5. 配置切面:將切面類註冊到 Spring 容器中,以便 Spring 能夠識別並處理它。這通常透過 Java 配置或 XML 配置來完成。

    @Aspect
    @Component // 或者使用 @Configuration 和 @EnableAspectJAutoProxy  
    public class LoggingAspect {

        // 定義一個切入點表示式  
        @Pointcut("execution(* com.example.service.*.*(..))")
        public void serviceLayerExecution() {}

        // 使用切入點表示式和 @Before 註解定義前置通知  
        @Before("serviceLayerExecution()")
        public void logBeforeServiceMethod(JoinPoint joinPoint) {
            System.out.println("Before executing " + joinPoint.getSignature().getName());
        }
//         使用切入點表示式和 @Around 註解定義前置通知
//        @Around("serviceLayerExecution()")
//        public void logBeforeServiceMethod(JoinPoint joinPoint) {
//            System.out.println("Around executing " + joinPoint.getSignature().getName());
//        }

        // 類似地,你可以定義其他型別的通知,如 @After、@AfterReturning、@AfterThrowing

注意事項

  • 確保你的 Spring 容器已經啟用了 AOP 支援,這通常透過 @EnableAspectJAutoProxy 註解在配置類上實現。
  • 切入點表示式是 Spring AOP 的強大功能之一,它允許你精確地指定哪些方法需要被增強。
  • 在切面類中定義的通知方法不應有返回值(除了環繞通知),並且它們的引數列表應該與 Spring AOP 要求的引數型別相匹配。
  • 具體使用按照自己程式碼的業務邏輯

6. @Autowired

Spring 框架中用於實現依賴注入的一個核心註解。它使得 Spring 容器能夠自動地識別和注入標註了 @Autowired 的欄位、構造器引數或方法引數所需的 bean。這極大地簡化了依賴管理,使得開發者可以更加專注於業務邏輯的實現,而不是如何配置和注入依賴

工作原理

當 Spring 容器啟動時,它會掃描被 @Component、@Service、@Repository 或 @Controller 等註解標記的類,並將這些類的例項作為 bean 註冊到 Spring 容器中。然後,對於每一個標註了 @Autowired 的欄位、構造器或方法,Spring 容器會嘗試在容器中查詢一個型別匹配的 bean,並將其注入到被註解的位置。

使用場景

  • 欄位注入:直接在類的欄位上使用 @Autowired 註解,Spring 容器會自動將匹配的 bean 注入到這個欄位中。
@Autowired  
private UserRepository userRepository;
  • 構造器注入:在類的構造器上使用 @Autowired 註解,Spring 容器會在建立類的例項時自動注入構造器引數所需的 bean。
@Autowired  
public UserService(UserRepository userRepository) {  
    this.userRepository = userRepository;  
}
  • 設定方法注入(Setter Injection):在類的 setter 方法上使用 @Autowired 註解,Spring 容器會在呼叫這個方法時自動注入所需的 bean。
@Autowired  
public void setUserRepository(UserRepository userRepository) {  
    this.userRepository = userRepository;  
}

Demo

image-20240923112722794

優點

  • 減少程式碼耦合:透過依賴注入,類之間的耦合度降低,更易於維護和測試。
  • 易於配置:使用 @Autowired 可以簡化配置過程,減少 XML 配置或 Java 配置的複雜性。
  • 支援自動裝配:Spring 容器能夠自動地識別並注入依賴關係,提高了開發效率。

注意事項

  • 可選依賴:如果某個依賴是可選的,可以在 @Autowired 註解後新增 required = false 屬性,這樣即使沒有匹配的 bean,Spring 也不會丟擲異常。
  • 多個候選者:如果 Spring 容器中有多個型別匹配的 bean,並且你需要注入其中一個,那麼可能需要使用 @Qualifier 註解來指定具體要注入哪一個 bean。
  • 迴圈依賴:@Autowired 預設支援構造器注入的迴圈依賴,但如果是透過欄位注入的迴圈依賴,可能需要額外的配置或避免使用。

7. @Bean

Spring 框架中的一個核心註解,它主要用於在配置類中宣告方法,並將這些方法的返回值註冊為 Spring 容器中的 Bean

作用

  • 宣告 Bean:@Bean 註解用於告訴 Spring 容器,被註解的方法將返回一個物件,該物件要註冊為 Spring 應用上下文中的 Bean。
  • 管理 Bean:一旦物件被註冊為 Bean,Spring 容器將負責其生命週期的管理,包括建立、裝配和銷燬等。

使用

  • 配置類:@Bean 註解通常用在帶有 @Configuration 註解的類中,這些類被稱為配置類。
  • 方法級別:@Bean 是一個方法級別上的註解,用於標記那些將返回物件作為 Bean 的方法。
@Configuration  
public class AppConfig {  
  
    @Bean  
    public UserService userService() {  
        return new UserService();  
    }  
}

特性

  • 依賴注入:@Bean 方法可以依賴其他 Bean,這些依賴將透過方法引數自動注入。
  • 生命週期回撥:可以使用 @PostConstruct 和 @PreDestroy 註解來定義 Bean 初始化後和銷燬前的回撥方法。
  • 指定名稱和別名:可以使用 @Bean 註解的 name 或 value 屬性來指定 Bean 的名稱和別名。
  • 指定作用域:可以使用 @Scope 註解來指定 Bean 的作用域,如 singleton(單例)、prototype(原型)等。

注意事項

  • 方法呼叫:雖然 @Bean 方法可以被呼叫,但通常不建議直接呼叫它們來獲取 Bean 例項,而應該透過 Spring 容器來獲取。
  • 唯一性:在同一個配置類中,@Bean 方法定義的 Bean 名稱預設是方法名,如果有多個方法返回相同型別的物件但名稱不同,則它們會被註冊為不同的 Bean。
  • 過載方法:雖然 Java 支援方法過載,但在使用 @Bean 註解時要小心,因為 Spring 容器可能無法正確處理過載的 @Bean 方法,導致不可預測的行為。
  • @Autowired:用於自動裝配 Bean,與 @Bean 配合使用,可以實現依賴的自動注入。
  • @Component、@Repository、@Service、@Controller:這些註解也是用於定義 Bean 的,但它們通常用於標註具體的類,而 @Bean 是用於標註配置類中的方法。
  • **@Bean **:是 Spring 框架中定義和管理 Bean 的重要工具,透過它,開發者可以靈活地在配置類中宣告和管理 Bean,從而實現依賴注入和物件管理的目的。

8. @Component

Spring 框架中的一個核心註解,它主要用於標識一個類作為 Spring 容器中的元件,成為Spring管理的Bean。當使用基於註解的配置和類路徑掃描時,這些類被視為自動檢測的候選物件。同時@Component還是一個元註解。

作用

  • 元件標識:@Component 註解用於告訴 Spring 容器,被註解的類是一個元件,應該被 Spring 管理。
  • 自動掃描:當使用基於註解的配置時,Spring 容器會掃描帶有 @Component 註解的類,並自動例項化它們作為 Spring 應用上下文中的 Bean。

使用

  • 通用元件:當一個類不好歸類到特定的註解(如 @Controller、@Service、@Repository)時,可以使用 @Component 進行標註。
  • 簡化配置:@Component 註解簡化了 Spring 應用的配置過程,使得開發人員能夠更加專注於業務邏輯的實現。

衍生註解

  • @Component 有三個常見的衍生註解:@Controller、@Service 和 @Repository。
    • @Controller:用於標識控制器類,處理 Web 請求。
    • @Service:用於標識服務層類,提供業務邏輯。
    • @Repository:用於標識資料訪問物件(DAO),提供資料訪問功能。
      這些衍生註解不僅簡化了元件的標識,還帶來了額外的好處,如異常轉換(@Repository)或 MVC 控制功能(@Controller)

依賴注入

  • 被 @Component 註解的類可以和其他類一樣進行自動裝配。例如,可以在另一個元件中使用 @Autowired 註解來自動注入一個被 @Component 註解的元件。
  • @Component 也支援指定元件的名稱,使用 @Qualifier 註解可以根據名稱來裝配元件。

注意事項

  • 雖然 @Component 註解非常靈活,但在實際開發中,建議根據元件的用途選擇合適的衍生註解(如 @Controller、@Service、@Repository),以便更好地組織和管理程式碼。
  • 當使用 @Component 註解時,要確保 Spring 容器能夠掃描到被註解的類。這通常透過設定 - -@ComponentScan 註解或相應的 XML 配置來實現。

9. @ComponentScan

用於指定 Spring 容器應該掃描哪些包來查詢並註冊帶有特定註解的類(如 @Component、@Service、@Repository、@Controller 等)作為 Spring Bean

作用

根據定義的掃描路徑,把符合掃描規則的類裝配到 Spring 容器中。這樣,Spring 容器就能夠管理這些類的生命週期,並提供依賴注入等功能。

基本屬性

@ComponentScan 註解包含多個屬性,用於自定義元件掃描的行為:

  • basePackages:指定需要掃描的包名,可以是一個字串陣列,也可以使用點號分隔的包路徑。
  • basePackageClasses:指定包中的某些類,Spring 會掃描這些類所在的包及其子包。
  • value:與 basePackages 功能相同,用於指定掃描的包名。
  • useDefaultFilters:是否使用預設的過濾器。如果設定為 true,則掃描所有帶有 @Component、@Service、@Repository 和 @Controller 註解的類。如果設定為 false,則不會使用預設的過濾器,此時可以透過 includeFilters 和 excludeFilters 屬性來自定義過濾規則。
  • includeFilters:指定 Spring 應該包含哪些型別的類。可以包含多個過濾器,每個過濾器都包含一個型別和一個類。
  • excludeFilters:指定 Spring 不應該包含哪些型別的類。用法與 includeFilters 類似。

Demo

例如包結構如下:

com  
└── example  
    └── myapp  
        ├── AppConfig.java  
        └── service  
            ├── UserService.java  
            └── ProductService.java

在 UserService.java 和 ProductService.java 中,我們分別使用 @Service 註解標註了這兩個類。然後,在 AppConfig.java 配置類中,我們可以使用 @ComponentScan 註解來指定 Spring 應該掃描的包:

@Configuration  
@ComponentScan(basePackages = "com.example.myapp")  
public class AppConfig {  
    // 這裡可以定義其他配置 Bean 和設定  
}

在這個例子中,@ComponentScan 註解被用於 AppConfig 類上,指定 Spring 應該掃描 com.example.myapp 包及其子包,以將元件註冊為 Spring Bean。

自定義過濾器

如果需要更細粒度的控制,可以透過 includeFilters 和 excludeFilters 屬性來自定義過濾規則。例如,只掃描帶有特定註解的類等

@ComponentScan(  
    basePackages = "com.example.myapp",  
    useDefaultFilters = false,  
    includeFilters = {  
        @Filter(type = FilterType.ANNOTATION, classes = {MyCustomAnnotation.class})  
    }  
)

10. @Configuration

它用於指示一個類宣告瞭一個或多個 @Bean 方法,並且這些 @Bean 方法將被 Spring 容器管理,用於生成和管理 Spring 應用上下文中的物件(即 beans)。當你使用 @Configuration 註解一個類時,該類就變成了一個配置類(configuration class),Spring 容器會在啟動時處理這個類,並識別出其中的 @Bean 方法。

主要特點

  • 配置類:@Configuration 註解的類被視為一個配置類,它允許你透過 @Bean 註解的方法來定義和初始化 beans。
  • 完全控制:透過配置類,你可以完全控制你的 Spring 應用上下文中的 bean 的建立和配置。
  • JavaConfig:@Configuration 是 JavaConfig 的一部分,JavaConfig 是指使用 Java 類和註解來代替傳統的 XML 檔案來配置 Spring 應用的方式。
  • 環境抽象:配置類還可以與 @Profile、@PropertySource 等註解結合使用,以支援更復雜的配置需求,如環境特定的配置和屬性檔案載入。

Demo

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
  
@Configuration  
public class AppConfig {  
  
    @Bean  
    public MyService myService() {  
        return new MyServiceImpl();  
    }  
}

AppConfig 是一個配置類,它定義了一個名為 myService 的 @Bean 方法。當 Spring 容器啟動時,它會呼叫 myService 方法來建立 MyService 介面的一個實現(MyServiceImpl),並將其註冊為 Spring 應用上下文中的一個 bean。這樣,你就可以在其他 Spring 管理的元件中透過自動裝配(如 @Autowired)來注入這個 MyService bean 了。

注意事項

  • 當你在配置類中使用 @Bean 註解的方法時,Spring 容器會確保每個 bean 只有一個例項(除非你在 @Bean 方法上使用了特定的作用域註解,如 @Scope)。
  • 配置類本身也是由 Spring 容器管理的,但它不是透過 @Bean 方法定義的。相反,它是透過 Spring 容器在啟動時掃描到的帶有 @Configuration 註解的類來識別的。
  • 配置類中的 @Bean 方法可以互相呼叫,以構建 bean 之間的依賴關係。但是,要注意避免迴圈依賴,因為這會導致 Spring 容器在啟動時丟擲異常。

11. @ConfigurationProperties

它主要用於將配置檔案(如 application.properties 或 application.yml)中的屬性繫結到 Java 物件上。這個註解極大地簡化了配置屬性的讀取和管理,使得開發者能夠將外部配置與應用程式程式碼解耦,提高程式碼的可維護性和可擴充套件性。

主要特點

  • 屬性繫結:將配置檔案中的屬性繫結到 Java 物件的欄位上,無需手動編寫大量的 getter 和 setter 方法來讀取配置。
  • 型別轉換:支援將配置檔案中的字串自動轉換為 Java 物件的相應型別(如 int、boolean、List、Map 等)。
  • 預設值:當配置檔案中沒有指定某個屬性的值時,可以使用 Java 欄位的預設值或透過 @Value 註解指定預設值。
  • 驗證:支援對配置屬性進行有效性驗證,確保配置的正確性。
  • 鬆散繫結:支援鬆散繫結規則,即屬性的名稱不需要嚴格匹配,例如 my-property-name 可以繫結到 myPropertyName 欄位上。

Demo

    1. 新增註解:在 Java 類上新增 @ConfigurationProperties 註解,並指定需要繫結的配置檔案字首
@Component
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
    private String name;
    private int version;
    // getter 和 setter 方法
}
    1. 配置檔案:在 application.properties 或 application.yml 配置檔案中新增相應的屬性。
application.properties
myapp.name=My App Name
myapp.version=1.0.0
application.yml
myapp:
  name: My App Name
  version: 1.0.0
    1. 使用配置:透過 Spring 容器獲取 MyAppProperties 類的例項,並使用其中的屬性值。
@Autowired  
private MyAppProperties myAppProperties;  

public void doSomething() {  
    String name = myAppProperties.getName();  
    int version = myAppProperties.getVersion();  
    // 使用屬性值進行其他操作  
}

注意事項

  • 字首:@ConfigurationProperties 註解的 prefix 屬性必須小寫,否則會報錯。
  • JavaBean 介面:被 @ConfigurationProperties 註解的類需要遵循 JavaBean 規範,即提供公共的 getter 和 setter 方法。
  • 容器元件:只有被 Spring 容器管理的元件(如透過 @Component、@Service 等註解標註的類)才能使用 @ConfigurationProperties 註解的功能。
  • 配置檔案處理器:可以匯入 Spring Boot 的配置檔案處理器依賴,以便在編寫配置時獲得程式碼提示。

12. @ContextConfiguration

Spring 測試場景中經常使用,它主要用於載入和配置 Spring 上下文(ApplicationContext)。這個註解允許開發者指定要載入的配置檔案或配置類的位置,以便在執行時或測試時能夠正確地構建和初始化 Spring 上下文。

作用

  • 載入配置檔案:用於指定 Spring 配置檔案的位置,這些配置檔案包含了 Spring 應用程式的配置資訊,如 bean 的定義、資料來源配置等。
  • 載入配置類:也可以用來指定一個或多個包含 @Configuration 註解的 Java 配置類的位置。

使用

@ContextConfiguration 註解可以透過兩種主要方式使用:

    1. 指定配置檔案:
      使用 locations 屬性來指定 XML 配置檔案的位置。可以指定一個或多個配置檔案,多個檔案之間用逗號或陣列語法分隔。
      示例:@ContextConfiguration(locations = { "classpath:applicationContext.xml", "classpath:test-context.xml" })
    1. 指定配置類:
      使用 classes 屬性來指定一個或多個配置類的位置。這些類必須包含 @Configuration 註解。
      示例:@ContextConfiguration(classes = { TestConfig.class, AnotherTestConfig.class })

原理

  • 當使用 @ContextConfiguration 註解時,Spring 容器會根據指定的配置檔案或配置類來建立和初始化應用程式上下文。
  • 如果指定了 XML 配置檔案,Spring 容器會透過相應的 ContextLoader(如 GenericXmlContextLoader)來載入這些 XML 檔案。
  • 如果指定了配置類,Spring 容器則會使用這些配置類中定義的 @Bean 方法來建立和註冊 bean。

13. @Controller

用於宣告一個類作為 Spring MVC 控制器(Controller)。當一個類被 @Controller 註解標記時,Spring 容器會檢測到這個類,並將其註冊為一個 Spring MVC 控制器,從而能夠處理透過 HTTP 請求對映的方法。

作用

  • 定義控制器:@Controller 註解將一個類標記為 Spring MVC 控制器,這意味著這個類中的方法可以處理來自客戶端的 HTTP 請求。
  • 請求對映:雖然 @Controller 註解本身不直接處理請求對映,但它常與 @RequestMapping 或其派生註解(如 @GetMapping、@PostMapping 等)一起使用,以將 HTTP 請求對映到控制器中的特定方法上。
  • 檢視解析:控制器方法通常返回一個檢視名稱或 ModelAndView 物件,Spring MVC 會根據這個返回值找到相應的檢視模板,並將其渲染為 HTML 響應返回給客戶端。
  • 資料繫結:控制器方法可以接收請求引數、路徑變數等,並自動將其繫結到方法引數上,這簡化了資料的提取和處理過程。

Demo

  • 新增 @Controller 註解:在類定義前新增 @Controller 註解,將類標記為控制器。
@Controller  
public class MyController {  
}
  • 定義請求處理方法:在控制器類中定義方法,並使用 @RequestMapping 或其派生註解來對映 HTTP 請求。
@Controller  
public class MyController {  

    @GetMapping("/hello")  
    public String hello(Model model) {  
        model.addAttribute("message", "Hello, Spring MVC!");  
        return "hello"; // 返回檢視名稱,Spring MVC 會找到相應的檢視模板進行渲染  
    }  
}
  • 配置檢視解析器:在 Spring MVC 的配置中,需要配置檢視解析器(ViewResolver),以便 Spring MVC 能夠根據控制器方法返回的檢視名稱找到相應的檢視模板。
@Bean  
public InternalResourceViewResolver viewResolver() {  
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();  
    resolver.setPrefix("/WEB-INF/views/");  
    resolver.setSuffix(".jsp");  
    return resolver;  
}

注意事項

  • 不要與 @RestController 混淆:@RestController 是 @Controller 和 @ResponseBody 的組合註解,它用於建立 RESTful Web 服務。如果你的控制器方法主要返回 JSON 或 XML 等資料而不是檢視,則應該使用 @RestController。
  • 路徑匹配:在 @RequestMapping 註解中定義的路徑是相對於應用程式的上下文路徑的。
  • 方法引數和返回值:控制器方法可以接收各種型別的引數,如 @RequestParam、@PathVariable、Model 等,並可以返回 String(檢視名稱)、ModelAndView、ResponseEntity、void(配合 HttpServletResponse 使用)等。
  • 異常處理:可以透過 @ExceptionHandler 註解來定義異常處理方法,以處理控制器中丟擲的異常。
  • 攔截器:可以透過實現 HandlerInterceptor 介面來建立攔截器,並在 Spring MVC 配置中註冊它們,以便在請求處理流程中的不同階段執行自定義的程式碼。

14. @ExceptionHandler

Spring MVC 中的一個註解,用於處理控制器中丟擲的異常。當你在控制器中處理請求時,可能會遇到各種異常情況,比如資料驗證失敗、資源找不到、許可權不足等。使用 @ExceptionHandler 註解,你可以定義一個或多個方法來專門處理這些異常,從而避免在控制器方法中直接處理異常邏輯,使程式碼更加清晰和易於維護。

使用

  • 定義異常處理方法:在控制器中,你可以使用 @ExceptionHandler 註解來標記一個或多個方法作為異常處理方法。這些方法需要接收一個異常型別的引數,並可以返回一個檢視名稱、ModelAndView 物件、ResponseEntity 或其他任何 Spring MVC 支援的響應型別。
  • 指定異常型別:@ExceptionHandler 註解可以指定一個或多個異常型別,表示該方法將處理哪些型別的異常。如果未指定異常型別,則該方法將作為預設異常處理器,處理所有未被其他 @ExceptionHandler 方法捕獲的異常。
  • 返回值:異常處理方法的返回值決定了如何響應客戶端。你可以返回一個檢視名稱來渲染一個錯誤頁面,或者返回一個包含錯誤資訊的 ResponseEntity 物件。

Demo

@Controller  
public class MyController {  
  
    // 處理特定型別的異常  
    @ExceptionHandler(value = MyCustomException.class)  
    public ResponseEntity<String> handleMyCustomException(MyCustomException ex) {  
        // 處理異常邏輯  
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("自定義異常處理");  
    }  
  
    // 處理所有未捕獲的異常(可選)  
    @ExceptionHandler(Exception.class)  
    public String handleAllExceptions(Exception ex) {  
        // 記錄日誌等操作  
        return "error"; // 返回錯誤頁面的檢視名稱  
    }  
  
    // 控制器方法  
    @GetMapping("/somePath")  
    public String someMethod() {  
        // 假設這裡丟擲了 MyCustomException 異常  
        throw new MyCustomException("這是一個自定義異常");  
    }  
  
    // 自定義異常類  
    public static class MyCustomException extends RuntimeException {  
        public MyCustomException(String message) {  
            super(message);  
        }  
    }  
}

注意事項

  • 全域性異常處理:如果你希望在整個應用程式中集中處理異常,而不是在每個控制器中分別處理,你可以建立一個實現了 HandlerExceptionResolver 介面的類,或者更簡單地,使用 @ControllerAdvice 註解來定義一個全域性異常處理類。
  • 異常優先順序:如果有多個 @ExceptionHandler 方法可以處理同一個異常,Spring MVC 會根據方法的定義順序(從上到下)來選擇第一個匹配的方法。因此,你應該注意異常處理方法的定義順序,以確保它們按照你期望的順序被呼叫。
  • 日誌記錄:在異常處理方法中,不要忘記記錄異常資訊到日誌中,以便在出現問題時進行除錯和追蹤。
  • 響應客戶端:確保你的異常處理方法能夠向客戶端返回清晰、有用的錯誤資訊,以提高使用者體驗和系統的可維護性。

15. @ModelAttribute

Spring框架中的一個註解,主要用於將HTTP請求中的資料繫結到模型物件,並在檢視中進行渲染。它可以應用於方法引數或方法本身,具有靈活的資料處理能力。

使用

  • 方法引數:
    當@ModelAttribute註解用於方法引數時,它表示從模型中獲取對應的屬性值,並將其繫結到方法引數上。這通常用於處理表單提交或URL中的查詢引數,自動將請求中的資料填充到對應的JavaBean物件中,並新增到模型中,便於後續方法或檢視使用。
@GetMapping("/users/{id}")  
public String getUser(@PathVariable("id") int userId, @ModelAttribute("user") User user) {  
    // 假設這裡根據userId從資料庫中獲取User物件  
    user = userService.getUserById(userId);  
    // 方法執行時,user引數已經包含了從資料庫獲取的User物件  
    // ...  
    return "userPage";  
}

@ModelAttribute("user")註解將請求中或模型中名為"user"的屬性繫結到User型別的引數user上。但請注意,這裡的實際使用場景可能有所不同,因為通常我們不會將@ModelAttribute用於已經透過@PathVariable等註解獲取了資料的引數上。這裡的示例主要是為了說明@ModelAttribute在方法引數上的用法。

  • 方法級別:
    當@ModelAttribute註解用於方法本身時,它表示該方法的返回值應該被新增到模型中。這常用於在多個請求處理方法之前,準備共用的模型資料。
@ModelAttribute  
public void addAttributes(Model model) {  
    model.addAttribute("msg", "Hello, Spring MVC!");  
}  
  
@GetMapping("/")  
public String home() {  
    // 這裡可以直接使用模型中的"msg"屬性  
    // ...  
    return "homePage";  
}

addAttributes方法使用了@ModelAttribute註解,其返回值(實際上是void,但透過model.addAttribute方法向模型中新增資料)會在每個請求處理方法之前執行,向模型中新增了一個名為"msg"的屬性。這樣,在後續的請求處理方法(如home方法)中就可以直接使用這個屬性了。

特點

  • 自動繫結:可以自動將請求引數繫結到模型物件,簡化了資料繫結的過程。
  • 靈活配置:透過指定屬性名稱,可以靈活控制模型中的屬性名稱。
  • 優先順序:@ModelAttribute註解的方法會優先於控制器中的其他請求處理方法執行,確保模型資料在請求處理之前就已經準備好。

注意事項

  • @ModelAttribute註解的方法會在控制器中的每個請求處理方法之前執行(除非有特定的條件阻止其執行),因此在使用時需要謹慎,避免不必要的效能開銷。
  • 當@ModelAttribute註解用於方法引數時,如果模型中不存在對應的屬性,Spring會嘗試從請求中查詢並繫結資料;如果模型中已存在對應的屬性,則直接使用模型中的屬性值。
  • 在使用@ModelAttribute註解時,可以透過指定屬性名稱來控制模型中的屬性名稱,未指定時則預設使用返回型別的首字母小寫作為屬性名稱(對於方法級別的@ModelAttribute)。

16. @Transactional

Spring 框架中用於宣告式事務管理的一個註解。它允許開發者透過簡單的註解來宣告某個方法或類需要事務支援,而無需編寫複雜的事務管理程式碼。Spring 會在執行時自動為這些方法或類建立代理物件,並在這些物件的方法執行時應用事務管理。

使用

  • 業務邏輯需要保證資料一致性:當多個資料庫操作需要作為一個整體來執行時,使用 @Transactional 可以確保這些操作要麼全部成功,要麼在遇到錯誤時全部回滾,從而保持資料的一致性。
  • 簡化事務管理:透過宣告式事務管理,開發者可以將事務管理的邏輯從業務程式碼中分離出來,專注於業務邏輯的實現,而無需直接處理事務的開啟、提交或回滾等繁瑣事務。
  • 提高程式碼的可讀性和可維護性:使用 @Transactional 註解可以使程式碼更加簡潔明瞭,易於理解和維護。

使用

@Transactional 可以應用於介面定義、介面中的方法、類定義或類中的方法上。但是,請注意,由於 Spring 代理機制的限制,該註解在介面定義或介面方法上的效果可能不如預期,因此通常建議將其應用於具體的類方法上。

@Service  
public class MyService {  
  
    @Transactional  
    public void myMethod() {  
        // 執行資料庫操作  
    }  
}

myMethod 方法被標記為事務性的。當這個方法被呼叫時,Spring 會自動為這個方法的執行建立一個事務上下文,並在方法執行結束時根據是否出現異常來決定是提交事務還是回滾事務。

屬性

@Transactional 註解還提供了多個屬性,允許開發者對事務的行為進行更細緻的控制,例如:

  • propagation:事務的傳播行為,定義了當前方法如何與已存在的事務進行互動。
  • isolation:事務的隔離級別,定義了事務中的修改對其他事務的可見性。
  • timeout:事務的超時時間,超過這個時間限制,事務將被自動回滾。
  • readOnly:標記事務是否為只讀事務,只讀事務用於不需要修改資料的場景,可以提高效能。
  • rollbackFor 和 rollbackForClassName:定義了哪些異常會導致事務回滾。
  • noRollbackFor 和 noRollbackForClassName:定義了哪些異常不會導致事務回滾。

注意事項

  • 方法可見性:@Transactional 註解的方法必須是 public 的,因為 Spring AOP 是透過代理機制來實現的,而代理機制要求被代理的方法必須是 public 的。
  • 自呼叫問題:在同一個類中,一個 @Transactional 註解的方法呼叫另一個 @Transactional 註解的方法時,事務的傳播行為可能不會按預期工作,因為自呼叫不會透過代理物件,因此事務管理不會被觸發。
  • 異常處理:預設情況下,執行時異常和錯誤會導致事務回滾,而受檢異常則不會。但是,可以透過 @Transactional 註解的 rollbackFor 和 noRollbackFor 屬性來自定義哪些異常會導致事務回滾。

17. @Value

Spring 框架中的一個註解,它用於注入配置檔案(如 properties 或 YAML 檔案)中的值到 Spring 管理的 bean 的欄位中。這個註解通常與 @ConfigurationProperties 或直接在 Spring 的元件(如 @Component、@Service、@Controller 等)中使用,以便從外部配置源(如 application.properties 或 application.yml 檔案)中讀取值。

使用

  • 注入基本型別值:如字串、整數、布林值等。
  • 注入複雜型別值:如使用 SpEL(Spring Expression Language)表示式來注入更復雜的值或執行一些操作。
  • 與 @ConfigurationProperties 一起使用:雖然 @ConfigurationProperties 提供了更強大的方式來繫結一組配置到 Java 物件,但 @Value 對於簡單的值注入來說仍然非常有用。

Demo

app.name=MyApp  
app.description=This is my application  
app.enabled=true  
app.number=123
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.stereotype.Component;  
  
@Component  
public class MyAppProperties {  
  
    @Value("${app.name}")  
    private String name;  
  
    @Value("${app.description}")  
    private String description;  
  
    @Value("${app.enabled}")  
    private boolean enabled;  
  
    @Value("${app.number}")  
    private int number;  
  
    // getters and setters  
}

注意事項

  • SpEL 表示式:@Value 註解還支援 SpEL 表示式,允許你執行更復雜的操作,如字串連線、條件判斷等。
  • 預設值:如果配置檔案中沒有找到對應的屬性,你可以為 @Value 註解提供一個預設值,例如 @Value("${some.property:defaultValue}")。
  • 型別安全:雖然 @Value 註解提供了方便的值注入方式,但它可能不如 @ConfigurationProperties 那樣型別安全,因為 @ConfigurationProperties 允許你透過 JavaBean 驗證來驗證配置屬性的值。
  • 環境變數和命令列引數:Spring Boot 還允許你透過環境變數和命令列引數來覆蓋 application.properties 或 application.yml 檔案中的值。這些值同樣可以透過 @Value 註解注入到你的應用中。

18. @WebAppConfiguration

Spring框架中的一個類級別的註解,主要用於Spring MVC的整合測試中,以指定測試類所載入的ApplicationContext應該是一個WebApplicationContext。這個註解在測試過程中模擬了ServletContext,並構建了一個WebApplicationContext,從而為測試環境提供了Web應用程式的環境。

作用

  • 整合測試:主要用於Spring MVC應用程式的整合測試中,確保測試能夠執行在Web應用程式的上下文中。
  • 模擬環境:透過模擬ServletContext,使得測試能夠更接近實際的Web執行環境。

特性

  • 類級別註解:必須應用於測試類上,而不是測試方法。
  • 自動配置:在Spring Boot應用中,當@WebAppConfiguration被應用到一個@Configuration類上時,Spring Boot會自動配置一個Web環境,包括啟動Servlet容器(如Tomcat)和處理HTTP請求等。
  • 結合使用:通常與@ContextConfiguration註解一起使用,以指定WebApplicationContext的配置位置或配置類。

Demo

import org.springframework.test.context.ContextConfiguration;  
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
import org.springframework.test.context.web.WebAppConfiguration;  
import org.springframework.test.web.servlet.MockMvc;  
import org.springframework.test.web.servlet.setup.MockMvcBuilders;  
import org.springframework.web.context.WebApplicationContext;  
import org.junit.Before;  
import org.junit.Test;  
import org.junit.runner.RunWith;  
  
@RunWith(SpringJUnit4ClassRunner.class)  
@WebAppConfiguration  
@ContextConfiguration("classpath:spring/applicationContext.xml")  
public class MyWebControllerTests {  
  
    private MockMvc mockMvc;  
  
    @Autowired  
    private WebApplicationContext webApplicationContext;  
  
    @Before  
    public void setup() {  
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();  
    }  
  
    @Test  
    public void testMyController() throws Exception {  
        // 使用mockMvc來模擬HTTP請求並驗證響應  
    }  
}

注意事項

  • Spring版本:在Spring 4.0及其之後的版本中,雖然@WebAppConfiguration仍然可用,但Spring提供了更靈活的方式來指定ApplicationContext,因此,在某些情況下,可能不再需要顯式地使用@WebAppConfiguration。
  • 資源路徑:@WebAppConfiguration允許透過其value()屬性來覆蓋預設的Web資源路徑,從而提供更靈活的配置選項。
  • 繼承性:自Spring Framework 5.3起,@WebAppConfiguration註解可以從包圍(enclosing)測試類中自動繼承,這簡化了註解的使用和管理。

19. @Order

用於定義Spring IOC容器中Bean的執行順序的優先順序(這裡的順序也可以理解為存放到容器中的先後順序)。它並不直接控制Bean的載入順序,而是影響Bean在特定場景下的執行順序,如依賴注入、事件監聽、攔截器/過濾器執行等。

使用

  • Bean載入順序
    在配置類中,可以使用@Order註解來指定Spring容器中Bean的建立順序。這對於依賴於其他Bean初始化順序的Bean特別有用。需要注意的是,@Order並不嚴格保證Bean的載入順序,特別是在併發環境下,但它提供了一個執行的優先順序指導。
  • 過濾器和攔截器順序
    在Web應用中,@Order註解可用於指定過濾器和攔截器的執行順序。透過設定不同的@Order值,可以確保它們按照指定的順序執行。
  • 事件監聽器順序
    在Spring框架中,@Order註解可用於指定事件監聽器的執行順序。這有助於確保事件監聽器按照特定的順序接收和處理事件。
  • AOP切面順序
    在使用Spring AOP進行方法攔截時,@Order註解可用於指定切面的執行順序。透過設定不同的@Order值,可以控制切面的執行順序,從而實現對方法的多層次攔截。
  • JUnit測試執行順序
    在JUnit測試中,@Order註解也可用於定義測試方法的執行順序。這有助於確保測試按照預期的順序執行,尤其是在測試之間存在依賴關係時。

Demo

@Component  
@Order(1)  
public class FirstBean {  
    // ...  
}  
@Component  
@Order(2)  
public class SecondBean {  
    // ...  
}

FirstBean將在SecondBean之前被建立(或按優先順序執行,具體取決於上下文)。

注意事項

  • 順序值
    @Order註解接收一個整數值作為引數,表示順序。數值越低,優先順序越高,意味著該元件或操作會更早地被執行或建立。
  • 預設值
    如果@Order註解沒有指定值,它將使用Ordered.LOWEST_PRECEDENCE作為預設值,這通常是Integer.MAX_VALUE,表示最低優先順序。
  • 併發環境
    在併發環境下,@Order註解並不能保證嚴格的執行順序。它更多地是提供一個執行的優先順序指導。
  • 與@Priority的關係
    @Priority註解是JSR-250的一部分,它在功能上與@Order類似,但有更廣泛的應用,包括在CDI(Contexts and Dependency Injection)中。

20. @SpringBootTest

是Spring Boot中一個非常重要的測試註解,它簡化了整合測試的配置和執行過程,使得開發者能夠更容易地建立接近生產環境的測試環境。

作用

  • 建立應用上下文:@SpringBootTest註解的主要用途是在測試過程中方便地建立一個應用上下文(ApplicationContext)。它告訴Spring Boot去尋找一個主配置類(比如帶有@SpringBootApplication的類),並使用它來啟動Spring應用上下文。
  • 整合測試:該註解通常用於測試Spring元件,特別是那些需要與Spring容器互動的元件。它能夠模擬出一個完整的Spring Boot應用環境,包括載入所有的Spring配置和Bean,從而使得測試能夠在一個真實的應用環境中執行。

使用

  1. 預設行為:
  • 預設情況下,@SpringBootTest會載入application.properties或application.yml檔案中的配置,並啟動一個Spring應用上下文。
  • 如果你的應用有多個配置類,可以透過classes屬性指定要載入的配置類。
  1. 靈活的配置:
  • excludeAutoConfiguration:使用excludeAutoConfiguration屬性來排除特定的自動配置。
  • properties:使用properties屬性來指定測試時使用的屬性值,以覆蓋預設配置。
  • webEnvironment:透過webEnvironment屬性來指定Web環境,支援的模式包括MOCK(預設,模擬Servlet環境)、RANDOM_PORT(啟動內嵌的Web伺服器並監聽隨機埠)、DEFINED_PORT(啟動內嵌的Web伺服器並監聽指定的埠)等。
  1. 與其他註解結合使用:
  • @SpringBootTest可以與其他Spring註解一起使用,如@DataJpaTest、@RestClientTest等,以提供更具體的測試環境。
  • 如果需要在測試中使用模擬的Bean,可以結合使用@MockBean註解。
  • 當測試Spring MVC控制器時,可以結合使用@SpringBootTest和@WebMvcTest。
  1. 自動注入功能:
  • 在使用@SpringBootTest註解的測試類中,可以透過Spring的@Autowired註解自動注入需要的元件和配置,方便進行整合測試。

Demo

import org.junit.jupiter.api.Test;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.context.SpringBootTest;  
import static org.junit.jupiter.api.Assertions.assertNotNull;  
  
@SpringBootTest  
public class MyApplicationTests {  
  
    @Autowired  
    private MyService myService;  
  
    @Test  
    public void testService() {  
        // 使用myService進行一些測試操作...  
        assertNotNull(myService, "myService should not be null");  
        // 其他測試邏輯...  
    }  
}

@SpringBootTest註解確保了MyApplication的應用上下文被載入,從而使得MyService能夠被自動注入到測試類中。這樣我們就可以在測試中使用MyService,就像它被Spring管理一樣,進行整合測試。

21. @PointCut

AspectJ框架(一個面向切面程式設計的框架)中的一個核心註解,在Spring AOP(面向切面程式設計)中也被廣泛使用。它用於定義一個切入點(Pointcut),即指定在哪些連線點(Join Point)上應用某個切面(Aspect)的增強邏輯。

定義

  • 定義切入點表示式:@Pointcut註解後面跟著的是一個字串,這個字串是一個切入點表示式,用於指定哪些方法會被攔截或增強。
  • 表示式格式:通常使用execution表示式,格式為execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)。其中,各個部分都是可選的,並且可以用萬用字元(如*)來表示任意值。

組成

  • 修飾符匹配(modifier-pattern?):方法的修飾符,如public、protected等,可選。
  • 返回值匹配(ret-type-pattern):方法的返回型別,可以用*表示任意型別,也可以指定具體的型別。
  • 類路徑匹配(declaring-type-pattern?):方法所在的類路徑,可以指定具體的類名或包名,包名後可以用..表示該包及其子包下的所有類。
  • 方法名匹配(name-pattern):具體的方法名,也可以用表示任意方法名,或SomeMethod表示以SomeMethod結尾的方法名。
  • 引數匹配(param-pattern):方法的引數列表,可以用*表示任意引數,(String)表示一個String型別的引數,(String, int)表示兩個引數,第一個是String型別,第二個是int型別。也可以用(..)表示任意數量和型別的引數。
  • 異常型別匹配(throws-pattern?):方法丟擲的異常型別,可選。

用法

  • 匹配所有方法:@Pointcut("execution(* *(..))")
  • 匹配特定包下的所有公有方法:@Pointcut("execution(public * com.example.service..(..))")
  • 匹配特定類及其子包下的所有方法:@Pointcut("execution(* com.example.service..*(..))")
  • 組合表示式:可以使用&&、||、!等邏輯運算子來組合多個切入點表示式。
  • 重用切入點表示式:將切入點表示式定義在一個方法中,然後在其他通知(Advice)中透過方法名來引用這個切入點,從而實現程式碼的複用。

Demo

@Aspect
@Component
@Slf4j
@Order(1)
public class SqlLoggingAspect {

    //定義切點
    @Pointcut("execution(* org.example.mapper..*(..))")
    public void repositoryExecution() {}

    // 在切入點之前執行  
    @Before("repositoryExecution()")
    public void logBefore(JoinPoint joinPoint) {
        log.debug("Executing method: " + joinPoint.getSignature().getName());
        Object[] args = joinPoint.getArgs();
    }
}

注意事項

  • 可讀性和可維護性:將切入點表示式抽取到一個獨立的方法中,可以提高程式碼的可讀性和可維護性。
  • 效能考慮:雖然重用切入點表示式可以提高程式碼的可讀性和可維護性,但過多的抽象和組合可能會降低效能,因為每次執行通知時都需要解析和匹配切入點表示式。

22. @Service

Spring 框架中的一個註解,它用於標註在服務層(Service Layer)的元件上。Spring 框架的核心思想之一是依賴注入(Dependency Injection, DI),而 @Service 註解正是 Spring 依賴注入功能的一部分。透過使用 @Service 註解,Spring 能夠自動地檢測到被標註的類,並將其例項化、配置並管理起來,同時將這些例項注入到需要它們的類中(比如控制器層(Controller Layer)的類)。

作用

  • 服務層元件標識:@Service 註解的主要用途是告訴 Spring 這是一個服務層元件。服務層通常負責業務邏輯的實現,它位於表現層(如控制器層)和持久層(如資料訪問層)之間。
  • 自動裝配:Spring 容器能夠掃描到被 @Service 註解的類,並自動地將其註冊為 Spring 應用上下文中的一個 Bean。這樣,其他元件(如控制器)就可以透過依賴注入的方式使用這些服務層元件了。
  • 事務管理:雖然 @Service 註解本身並不直接提供事務管理功能,但服務層元件經常需要處理事務。Spring 允許你在服務層方法上使用 @Transactional 註解來宣告性地管理事務。

Demo

import org.springframework.stereotype.Service;  
  
@Service  
public class UserService {  
  
    // 這裡可以注入其他依賴,比如資料訪問層的元件  
  
    public User getUserById(Long id) {  
        // 實現根據使用者ID獲取使用者的業務邏輯  
        // ...  
        return new User();
    }  
  
    // 其他業務方法...  
}

UserService 類被 @Service 註解標註,表示它是一個服務層元件。Spring 容器會自動檢測到這個類,並將其註冊為一個 Bean,然後就可以在需要的地方透過依賴注入的方式使用這個服務了。

注意事項

  • 雖然 @Service 註解是 Spring 提供的,但它實際上是一個泛型的註解,可以用在任何層級的元件上。然而,按照 Spring 的最佳實踐,我們通常將 @Service 用於服務層元件,而將 @Repository 用於資料訪問層元件,將 @Controller 用於控制器層元件等。
  • 在使用 @Service 註解時,需要確保你的 Spring 配置(無論是基於 XML 的配置還是基於 Java 的配置)能夠掃描到被註解的類所在的包。這通常是透過在配置類上新增 @ComponentScan 註解來實現的。
  • 如果你使用的是 Spring Boot,那麼通常不需要顯式地進行包掃描配置,因為 Spring Boot 會自動掃描啟動類所在的包及其子包下的所有元件。

23. @SpingBootApplication

Spring Boot 中的一個核心註解,它主要用於標記 Spring Boot 應用的主配置類。這個註解是一個複合註解,它結合了多個其他 Spring 框架中的註解,以簡化 Spring Boot 應用的配置和啟動過程。

組成

@SpringBootApplication 註解實際上是以下三個註解的集合:

  • @SpringBootConfiguration:這是 @Configuration 的一個特殊形式,用於定義配置類。它表明該類可以使用 Spring Boot 的自動配置功能,並且能夠被 Spring 容器管理。
  • @EnableAutoConfiguration:這個註解啟用了 Spring Boot 的自動配置機制。Spring Boot 會根據專案的類路徑和依賴關係自動配置各種 Spring 框架和第三方庫的功能,減少手動配置的工作量。
  • @ComponentScan:這個註解用於指定 Spring 容器要掃描的元件的基礎包路徑。預設情況下,它會掃描當前包及其子包中的元件,如使用 @Component@Service@Repository@Controller 等註解的類,並將它們註冊為 Spring 應用上下文中的 Bean。

作用

  • 簡化配置:透過 @SpringBootApplication 註解,開發者可以快速地啟動並執行一個 Spring Boot 應用,而無需進行大量的手動配置。
  • 自動配置:Spring Boot 會根據專案的依賴和類路徑中的 Bean 自動配置應用程式的各個方面,如資料庫連線、MVC 配置等,提供開箱即用的功能。
  • 元件掃描:自動掃描並註冊帶有 @Component、@Service、@Repository 和 @Controller 等註解的類作為 Spring 的 Bean,使得開發者可以方便地使用和管理這些元件。
  • 啟動類標識:將帶有 @SpringBootApplication 註解的類標識為 Spring Boot 應用程式的入口點。在執行 Spring Boot 應用程式時,會首先載入並啟動被 @SpringBootApplication 註解標記的類,從而啟動整個應用程式。

Demo

@SpringBootApplication 註解會被新增到主類上

import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
  
@SpringBootApplication  
public class MySpringBootApplication {  
  
    public static void main(String[] args) {  
        SpringApplication.run(MySpringBootApplication.class, args);  
    }  
  
    // 這裡可以定義其他的方法或元件  
}

@SpringBootApplication 註解簡化了啟動 Spring Boot 應用的過程。當執行 main 方法時,Spring Boot 會自動進行配置並啟動應用。

自定義配置

@SpringBootApplication 註解還允許開發者透過其屬性進行自定義配置。例如,使用 exclude 屬性可以排除特定的自動配置類,以避免不需要的自動配置。

24. @Profile

主要用於定義特定的配置環境(profile),以便在不同的環境中載入不同的配置或Bean

作用

  • 環境區分:在軟體開發過程中,經常需要區分不同的環境,如開發環境(dev)、測試環境(test)、生產環境(prod)等。每個環境可能有不同的配置需求,如資料庫連線、日誌級別等。@Profile 註解允許開發者為不同的環境定義不同的配置,從而實現環境間的靈活切換。
  • 條件化Bean的建立:透過 @Profile 註解,可以指定某個Bean或配置類只在特定的環境下才會被建立和載入。這有助於減少不必要的資源載入,提高應用的啟動速度和執行效率。
  • 提高可維護性和可擴充套件性:透過為不同的環境定義不同的配置,可以使得應用更加模組化,易於維護和擴充套件。當需要新增新的環境或修改現有環境的配置時,只需修改對應的配置類或Bean即可,無需修改整個應用的程式碼。

使用

  1. 修飾類:@Profile 可以直接修飾配置類(即帶有 @Configuration 註解的類),表示該配置類及其內部的Bean定義只在指定的環境下有效。
@Configuration  
@Profile("dev")  
public class DevConfig {  
    // 定義開發環境特有的Bean  
}
  1. 修飾方法:在配置類中,@Profile 也可以修飾 @Bean 方法,表示該方法定義的Bean只在指定的環境下被建立。
@Configuration  
public class DataSourceConfig {  
      
    @Bean  
    @Profile("dev")  
    public DataSource devDataSource() {  
        // 返回開發環境的資料來源  
    }  

    @Bean  
    @Profile("prod")  
    public DataSource prodDataSource() {  
        // 返回生產環境的資料來源  
    }  
}
  1. 組合使用:@Profile 還支援組合使用多個環境名稱,用逗號分隔。這表示該配置或Bean在多個環境下都會生效。
@Bean  
@Profile("dev,test")  
public DataSource devTestDataSource() {  
    // 返回開發和測試環境共有的資料來源  
}

注意:使用的時候要啟用Profile
在 application.properties 或 application.yml 檔案中,透過設定 spring.profiles.active 屬性來指定當前啟用的Profile。

# application.properties  
spring.profiles.active=dev
# application.yml  
spring:  
  profiles:  
    active: dev

25. @Reponsitory

專門用於資料訪問層(DAO層)的元件

作用

  • 標識資料訪問層:@Repository 註解用於標識資料訪問層(DAO層)的類,這些類通常負責與資料庫進行互動,執行資料的CRUD(建立、讀取、更新、刪除)操作。
  • 自動檢測和管理:透過 @Repository 註解,Spring 容器能夠自動檢測並管理這些 DAO 元件,將它們作為 Bean 注入到應用的其他部分。
  • 異常處理:@Repository 註解還提供了與資料訪問相關的異常處理機制,它會自動將資料庫相關的異常轉換為 Spring 的資料訪問異常層次結構(如 DataAccessException),從而簡化了異常處理的複雜性。

與其他註解關係

  • @Component:@Repository 是 @Component 註解的一個特殊形式,專門用於資料訪問層。雖然它們都可以將類標記為 Spring 容器管理的元件,但 @Repository 提供了更明確的語義和額外的資料訪問支援。
  • @Service 和 @Controller:與 @Repository 類似,@Service 和 @Controller 也是 @Component 註解的擴充套件,分別用於服務層和控制器層。它們共同構成了 Spring 的分層架構。

使用

  • 關係型資料庫訪問:@Repository 註解可以應用於操作關係型資料庫的 DAO 類,透過 JDBC、JPA 等技術實現資料庫操作。
  • 非關係型資料庫訪問:同樣適用於操作非關係型資料庫的 DAO 類,如 MongoDB、Redis 等。
  • 訊息佇列操作:雖然不常見,但理論上 @Repository 註解也可以用於標記操作訊息佇列的元件,儘管這更多是由 @Service 或其他業務邏輯層元件來處理的。

Demo

@Repository
@Mapper
public interface UserMapper {
    List<UserModel> findAll();
    UserModel findByName(String username);
    String findPswByName(String userName);
    void save(UserModel user);
}
@Service
public class UserserviceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    // 登入操作
    public String login(UserModel user) {
        try {
            UserModel userExistN = userMapper.findByName(user.getUsername());
            if (userExistN != null) {
                String userExistP = userMapper.findPswByName(user.getUsername());
                if (userExistP.equals(user.getPassword())) {
                    return user.getUsername()+"登入成功,歡迎您!";
                }else{
                    return "登入失敗,密碼錯誤!";
                }
            }else {
                return "登入失敗,使用者不存在!";
            }
        }catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }
}

注意事項

  • 異常處理:雖然 @Repository 註解提供了自動的異常轉換機制,但在實際應用中,仍然需要根據業務需求進行適當的異常處理。
  • 依賴注入:在使用 @Repository 註解的類中,通常會透過 @Autowired 或其他依賴注入方式注入其他必要的元件或服務。
  • 配置:確保 Spring 配置類或啟動類上啟用了相應的自動掃描機制(如 @ComponentScan),以便 Spring 能夠掃描到並管理這些 DAO 元件。

26. @RequestBody

Spring MVC 和 Spring Boot 中常用的一個註解,它用於處理 HTTP 請求的 body 部分。當客戶端傳送一個請求到伺服器時,請求體(body)通常包含了要傳送到伺服器的資料。@RequestBody 註解告訴 Spring 的 DispatcherServlet,應該將請求體中的 JSON 或 XML 資料繫結到控制器(Controller)方法的引數上。

使用

  • POST 和 PUT 請求:在大多數情況下,@RequestBody 用於處理 POST 和 PUT 請求,因為這兩種請求型別通常用於提交資料到伺服器。
  • 接收 JSON 或 XML 資料:當客戶端傳送 JSON 或 XML 格式的資料時,@RequestBody 可以幫助將這些資料自動繫結到 Java 物件上。

原理

當控制器方法使用 @RequestBody 註解時,Spring 會使用 HttpMessageConverters 將請求體中的資料轉換為 Java 物件。HttpMessageConverters 是一組用於轉換 HTTP 請求和響應的類,它們負責將請求體中的資料轉換為 Java 物件,以及將 Java 物件轉換回響應體資料。

預設情況下,Spring Boot 提供了對 JSON 和 XML 的支援,因此你可以直接接收和傳送 JSON 或 XML 資料。但是,你也可以透過新增其他庫來支援其他格式的資料。

Demo

// User.java  
public class User {  
    private Long id;  
    private String name;  
    // 省略getter和setter方法  
}  
  
// UserController.java  
@RestController  
@RequestMapping("/users")  
public class UserController {  
  
    @PostMapping("/add")  
    public ResponseEntity<String> addUser(@RequestBody User user) {  
        // 這裡可以處理user物件,例如儲存到資料庫  
        return ResponseEntity.ok("User added successfully!");  
    }  
}

當客戶端傳送一個 POST 請求到 /users/add,並且請求體中包含了一個 JSON 格式的 User 物件時,Spring 會自動將這個 JSON 資料轉換成 User 類的例項,並將其作為 addUser 方法的引數傳入。

注意事項

  • 確保你的請求頭(Content-Type)正確設定為了 application/json 或其他相應的 MIME 型別,以便 Spring 知道如何解析請求體。
  • 如果請求體中的資料無法正確轉換成 Java 物件(例如,JSON 格式錯誤或欄位不匹配),Spring 會丟擲一個異常。你可以透過全域性異常處理來捕獲這些異常,並返回友好的錯誤訊息給客戶端。
  • 預設情況下,Spring 使用 Jackson 庫來解析 JSON 資料。如果你需要處理 XML 資料,可能需要新增 JAXB 或其他相關依賴。

27. @RequestMapping

Spring MVC 中一個非常核心的註解,它用於將 HTTP 請求對映到特定的處理器(比如控制器中的一個方法)上。這個註解可以宣告在類或方法上,用於定義請求的 URL、HTTP 方法(如 GET、POST)、請求引數、請求頭等資訊,以及它們如何被對映到特定的處理函式上。

主要屬性

  • value / path:指定請求的 URL 路徑。可以是具體的路徑,也可以是包含變數(如 {id})的路徑模板。
  • method:指定請求的型別(如 GET、POST)。這個屬性是 RequestMethod 列舉的一個值或它們的組合。
  • params:指定請求的必須包含或不能包含的引數。
  • headers:指定請求的必須包含或不能包含的 HTTP 頭資訊。
  • consumes:指定處理請求的提交內容型別(Content-Type),如 application/json。
  • produces:指定返回的內容型別,僅當請求頭中的(Accept)型別包含該指定型別才返回。

使用

  1. 類級別上的 @RequestMapping
@Controller  
@RequestMapping("/users")  
public class UserController {  
  
    @GetMapping("/{id}")  
    public String getUserById(@PathVariable("id") Long id, Model model) {  
        // 根據 id 獲取使用者資訊,並填充到 model 中  
        return "userDetail"; // 返回檢視名  
    }  
  
    @PostMapping  
    public String createUser(@RequestParam String name, Model model) {  
        // 建立使用者  
        return "userCreated";  
    }  
}

@RequestMapping("/users") 應用於 UserController 類上,這意味著這個類中的所有請求 URL 都會以 /users 開頭。然後,@GetMapping("/{id}") 和 @PostMapping 分別用於對映具體的 HTTP GET 和 POST 請求到不同的處理方法上。
2. 方法級別上的 @RequestMapping

@Controller  
public class MyController {  
  
    @RequestMapping(value = "/hello", method = RequestMethod.GET)  
    public String sayHello() {  
        return "hello"; // 返回檢視名  
    }  
  
    @RequestMapping(value = "/goodbye", method = RequestMethod.GET, params = "name")  
    public String sayGoodbye(@RequestParam String name) {  
        // 僅在請求中包含 'name' 引數時呼叫  
        return "goodbye";  
    }  
}

@RequestMapping 直接用於方法上,指定了請求的 URL 路徑、HTTP 方法以及請求引數。params = "name" 表示這個請求必須包含名為 name 的引數。

28. @ResponseBody

它用於將控制器的返回值繫結到 web 響應體(Response Body)上。當處理器方法被 @ResponseBody 註解時,Spring 會自動將方法的返回值寫入到 HTTP 響應(HttpServletResponse)中。這個過程通常涉及到使用訊息轉換器(Message Converters)將返回值轉換為適當的格式(如 JSON、XML 等),然後寫入到響應體中。

作用

  • RESTful Web 服務:在構建 RESTful Web 服務時,@ResponseBody 非常有用,因為它允許你直接將物件序列化為 JSON 或 XML,並作為 HTTP 響應傳送給客戶端。
  • Ajax 請求:在 Ajax 請求中,伺服器通常需要返回 JSON 或 XML 格式的資料,@ResponseBody 可以輕鬆實現這一點。

Demo

有一個使用者物件 User 和一個控制器方法,你想要將 User 物件以 JSON 格式返回給客戶端。

@RestController // 這是一個方便的註解,相當於在每個方法上都加了 @Controller 和 @ResponseBody  
public class UserController {  
  
    @GetMapping("/user/{id}")  
    public User getUserById(@PathVariable Long id) {  
        // 假設這裡有一個服務或DAO層呼叫,根據id返回User物件  
        User user = new User();  
        user.setId(id);  
        user.setName("John Doe");  
        // 由於這裡使用了 @RestController,或者如果只有這個方法使用了 @ResponseBody,  
        // Spring 將自動將 User 物件序列化為 JSON 並寫入響應體  
        return user;  
    }  
}  
  
// 如果你沒有使用 @RestController,但想要對單個方法應用 @ResponseBody,可以這樣做:  
  
@Controller  
public class UserController {  
  
    @GetMapping("/user/{id}")  
    @ResponseBody // 告訴 Spring MVC 返回的內容應該繫結到響應體上  
    public User getUserById(@PathVariable Long id) {  
        // ... 與上面的示例相同  
    }  
}

注意事項

  • 當你使用 @ResponseBody 時,Spring 會查詢合適的 HttpMessageConverter 來將你的返回值轉換為響應體所需的格式。
  • 如果你正在使用 Spring Boot,並且已經新增了 Spring Web Starter 依賴,那麼 Spring Boot 會自動配置一些常用的 HttpMessageConverter,如用於 JSON 的 Jackson 和用於 XML 的 JAXB。
  • @RestController 是 @Controller 和 @ResponseBody 的組合註解,用於構建 RESTful Web 服務。如果你發現你的控制器中的所有方法都需要 @ResponseBody,那麼使用 @RestController 會更簡潔。

29. @RestController

Spring 4.0 引入的一個註解,它是 @Controller 和 @ResponseBody 的組合註解。當你在一個類上使用 @RestController 註解時,意味著這個類中的所有方法都會預設應用 @ResponseBody 註解的效果,即方法的返回值會自動地繫結到 Web 響應體(Response Body)上,並且通常會被轉換為 JSON 或 XML 等格式(這取決於配置的訊息轉換器)。

作用

  • RESTful Web 服務:@RestController 是構建 RESTful Web 服務的理想選擇,因為它簡化了將物件序列化為 JSON 或 XML 併傳送到客戶端的過程。
  • 簡化配置:如果你發現你的控制器類中的大多數或所有方法都需要 @ResponseBody 註解,那麼使用 @RestController 可以減少重複的程式碼,並使你的控制器類更加簡潔。

Demo

@RestController  
public class UserController {  
  
    @GetMapping("/user/{id}")  
    public User getUserById(@PathVariable Long id) {  
        // 假設這裡有一個服務或DAO層呼叫,根據id返回User物件  
        User user = new User();  
        user.setId(id);  
        user.setName("John Doe");  
        // 由於使用了 @RestController,Spring 會自動將 User 物件序列化為 JSON 並寫入響應體  
        return user;  
    }  
  
    @PostMapping("/user")  
    public ResponseEntity<String> createUser(@RequestBody User user) {  
        // 假設這裡有一個服務層呼叫,用於建立使用者  
        // 儘管這裡返回的是 ResponseEntity,但 @RestController 仍然適用,因為它只關心返回值是否應該被寫入響應體  
        return ResponseEntity.ok("User created successfully");  
    }  
}

getUserById 方法返回一個 User 物件,而 createUser 方法返回一個 ResponseEntity 物件。由於 UserController 類被 @RestController 註解,Spring 會自動處理這兩個方法的返回值,將它們轉換為 JSON(或其他配置的格式)並寫入 HTTP 響應體中。

注意事項

  • 當你在一個類上使用 @RestController 時,該類中的所有處理方法都會被視為 @ResponseBody 方法,除非你在方法級別上明確地使用 @ResponseBody(false) 來覆蓋這個行為(但通常這不是必要的)。
  • @RestController 使得構建 RESTful Web 服務變得更加簡單和直接,因為它減少了需要編寫的樣板程式碼量。
  • 如果你需要在一個控制器類中混合使用 @ResponseBody 和非 @ResponseBody 方法(例如,某些方法返回檢視名稱而不是資料),那麼你應該使用 @Controller 而不是 @RestController,並在需要的地方顯式地新增 @ResponseBody 註解。

30. @Async

用於宣告一個非同步方法。當你在方法上使用 @Async 註解時,Spring 會在呼叫該方法時,在一個單獨的執行緒中非同步地執行它。這意味著呼叫者執行緒不需要等待被 @Async 註解的方法執行完成,而是可以繼續執行其他任務。

作用

  • 提高應用程式效能:透過非同步處理,可以避免在執行長時間執行的任務時阻塞主執行緒,從而提高應用程式的響應性和吞吐量。
  • 解耦:非同步處理可以幫助你解耦方法的呼叫和執行,使得方法的呼叫者不需要關心方法的執行細節和執行時間。

使用

為了使用 @Async 註解,你需要滿足以下條件:

  1. 配置非同步支援:在你的 Spring 配置中啟用非同步支援。這可以透過在配置類上新增 @EnableAsync 註解來實現。
  2. 將 @Async 註解應用於適當的方法:確保 @Async 註解被應用於公共的、非靜態的、非void返回型別(或在Java 8+中為CompletableFuture/Future等)的、且沒有被 final 修飾的方法上。
  3. 返回型別:通常,@Async 方法會返回一個 Future 或 CompletableFuture 物件,以便呼叫者可以檢查非同步方法的執行狀態或獲取結果。但是,也可以返回 void 或其他型別,但這樣呼叫者就無法直接知道非同步方法的執行結果或狀態。

Demo

@Configuration  
@EnableAsync  
public class AsyncConfig {  
    // 這裡通常不需要實現任何bean,只需要@EnableAsync註解來啟用非同步支援  
}
@Service  
public class AsyncService {  
  
    @Async  
    public Future<String> executeAsyncTask(int number) throws InterruptedException {  
        // 模擬長時間執行的任務  
        Thread.sleep(1000);  
        return new AsyncResult<>("AsyncTask completed with value " + number);  
    }  
  
    // 也可以返回void,但這樣呼叫者就無法獲取到執行結果  
    @Async  
    public void executeVoidAsyncTask(int number) {  
        // 同樣的長時間執行任務  
        System.out.println("Executing void async task with number " + number);  
    }  
}  
@RestController  
public class AsyncController {  
  
    @Autowired  
    private AsyncService asyncService;  
  
    @GetMapping("/async/{number}")  
    public ResponseEntity<String> asyncEndpoint(@PathVariable int number) throws ExecutionException, InterruptedException {  
        Future<String> future = asyncService.executeAsyncTask(number);  
        // 這裡可以執行其他任務,而不需要等待非同步方法完成  
        String result = future.get(); // 獲取非同步方法的執行結果,這將阻塞直到非同步方法完成  
        return ResponseEntity.ok(result);  
    }  
}

雖然 Future.get() 方法可以用來獲取非同步方法的執行結果,但它會阻塞呼叫執行緒直到非同步方法完成。如果你想要避免阻塞,可以使用 CompletableFuture 並利用它的非阻塞API來處理非同步結果。

注意事項

  • 當你在使用 @Async 註解時,確保不要在同一個類中呼叫非同步方法,因為 Spring 的代理機制(通常是基於JDK動態代理或CGLIB)只會對透過Spring容器呼叫的方法進行代理。如果你在同一個類的方法中呼叫另一個帶有 @Async 註解的方法,那麼這個呼叫將不會被非同步處理。
  • 非同步方法執行時的異常處理需要特別注意。如果你使用 Future.get() 來獲取結果,那麼非同步方法丟擲的任何未捕獲的異常都將被封裝為 ExecutionException 丟擲。如果你使用的是 CompletableFuture,則可以更靈活地處理異常,例如透過 exceptionally 方法來指定異常處理邏輯。

31. @AutoConfigureAfter

它主要用於指示某個自動配置類(Configuration Class)應該在指定的其他自動配置類之後進行自動配置。這個註解提供了一種機制來控制 Spring Boot 自動配置的順序,確保依賴關係的正確性,從而保證應用的正確性和可維護性。

作用

  • 控制自動配置順序:在 Spring Boot 中,有很多自動配置的類,它們會根據系統的環境、條件等自動進行配置。然而,這些配置類有時會依賴於其他的配置類。透過使用 @AutoConfigureAfter 註解,可以確保依賴的配置類先被載入和配置。
  • 保證依賴關係的正確性:當一個自動配置類需要使用另一個自動配置類中的 Bean 或配置時,使用 @AutoConfigureAfter 可以避免由於載入順序錯誤導致的依賴問題。

使用

  • 註解位置:@AutoConfigureAfter 註解只能用於配置類上,即被 @Configuration 註解修飾的類上。
  • 引數指定:在 @AutoConfigureAfter 註解的 value 屬性中,可以指定一個或多個類,這些類必須在指定的自動配置類之後進行自動配置。

Demo

@Configuration  
@AutoConfigureAfter(DataSourceAutoConfiguration.class)  
public class MyAutoConfiguration {  
    // ... 配置類的實現 ...  
}

MyAutoConfiguration 類將在 DataSourceAutoConfiguration 類之後進行自動配置。

注意事項

  • 指定的類必須已存在:@AutoConfigureAfter 註解中指定的類必須已經被 Spring Boot 自動配置或顯式定義,否則將丟擲 AutoConfigurationOrderFailedException 異常。
  • 多個配置類:如果有多個自動配置類都使用了 @AutoConfigureAfter 註解,那麼這些類將按照註解中指定的順序進行載入。
  • 與 @AutoConfigureBefore 的關係:@AutoConfigureBefore 是與 @AutoConfigureAfter 相對應的註解,用於指示某個自動配置類應該在指定的其他自動配置類之前進行自動配置。

32. @Cacheable

主要用於宣告性快取,即將方法的返回值快取起來,以便在後續相同方法的呼叫中可以直接從快取中獲取結果,而無需再次執行方法的實際邏輯。這樣做可以顯著提高系統的效能和響應速度,特別是在處理讀取操作頻繁但資料更新不頻繁的場景時。

作用

  • 減少資料庫訪問:對於需要從資料庫讀取資料的操作,使用 @Cacheable 可以避免重複的資料庫查詢,減輕資料庫壓力。
  • 提升效能:透過減少方法的執行次數,降低計算資源的消耗,從而提升系統的整體效能。

使用

在 Spring Boot 專案中,使用 @Cacheable 註解通常需要以下幾個步驟:

  • 新增依賴:在專案的 pom.xml 檔案中新增 Spring Boot 的快取啟動器依賴,如 spring-boot-starter-cache。
  • 開啟快取:在 Spring Boot 的啟動類上新增 @EnableCaching 註解,以開啟快取支援。
  • 配置快取:根據需要配置快取的型別(如 Redis、EhCache 等)和相關屬性。
  • 使用註解:在需要快取的方法上新增 @Cacheable 註解,並指定快取的名稱、鍵的生成策略等引數。

引數

  • value/cacheNames:指定快取的名稱,可以是一個字串或字串陣列,表示方法的結果可以被快取到哪些快取中。
  • key:指定快取的鍵,可以是一個 SpEL(Spring Expression Language)表示式,用於根據方法引數動態生成快取的鍵。如果不指定,則預設使用方法的引數作為鍵。
  • condition:指定快取的條件,是一個 SpEL 表示式,用於決定在何種情況下將方法的返回值快取起來。如果不指定,則預設快取所有結果。
  • unless:指定快取的排除條件,也是一個 SpEL 表示式,用於決定在何種情況下不將方法的返回值快取起來。如果不指定,則預設不排除任何結果。

Demo

@Service  
public class MyService {  
  
    @Cacheable(value = "myCache", key = "#id")  
    public String getData(int id) {  
        // 模擬耗時操作  
        try {  
            Thread.sleep(2000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        // 實際的資料獲取邏輯  
        return "Data for id: " + id;  
    }  
}

getData 方法的結果會被快取到名為 myCache 的快取中,快取的鍵是方法的引數 id。當再次呼叫 getData 方法並傳入相同的 id 時,如果快取中存在對應的結果,則直接返回快取中的值,而不會執行方法的實際邏輯。

注意事項

  • 快取一致性:在使用 @Cacheable 時,需要關注快取資料的一致性問題。如果快取的資料在外部被修改,而系統沒有感知到這種變化,就可能導致資料不一致的問題。
  • 快取穿透:當查詢一個不存在的資料時,快取中不會儲存該資料,導致每次查詢都會穿透到資料庫。可以透過布隆過濾器等機制來避免快取穿透。
  • 快取雪崩:當大量快取同時失效時,所有請求都會直接訪問資料庫,導致資料庫壓力驟增。可以透過設定快取的過期時間時加入隨機因子、使用多級快取等方式來避免快取雪崩。

33. @Conditional

用於在基於條件的情況下控制配置類的註冊或Bean的建立。這個註解是 Spring 4.0 引入的,作為 Spring 的條件化配置的一部分,它提供了一種靈活的方式來控制哪些配置或Bean應該被包含在Spring應用上下文中。

使用

@Conditional 註解通常與自定義條件類一起使用,這些條件類實現了 Condition 介面。透過實現 matches(ConditionContext, AnnotatedTypeMetadata) 方法,你可以定義何時應該包含特定的配置類或Bean。這種方法非常適合於根據執行時環境(如作業系統型別、JVM版本、特定的庫是否可用等)來條件化地包含配置。

工作原理

  1. 定義條件:首先,你需要定義一個或多個實現了 Condition 介面的類。在這個類中,你將實現 matches 方法,該方法根據給定的條件返回 true 或 false。
  2. 應用條件:然後,你可以將 @Conditional 註解應用於配置類或Bean方法上,並透過其 value 屬性指定你的條件類。如果條件類的 matches 方法返回 true,則配置類或Bean將被包含在Spring應用上下文中;如果返回 false,則將被忽略。

Demo

// 自定義條件類  
public class OnWindowsCondition implements Condition {  
    @Override  
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {  
        // 檢查作業系統是否為Windows  
        return System.getProperty("os.name").toLowerCase().contains("win");  
    }  
}  
  
// 使用@Conditional註解  
@Configuration  
public class AppConfig {  
  
    @Bean  
    @Conditional(OnWindowsCondition.class)  
    public MyWindowsSpecificBean myWindowsSpecificBean() {  
        return new MyWindowsSpecificBean();  
    }  
}
   MyWindowsSpecificBean 只有在作業系統為Windows時才會被建立並註冊到Spring應用上下文中。

注意事項

  • @Conditional 可以與 @Bean、@Configuration、@Component 等註解一起使用。
  • Spring提供了多個內建的條件註解,如 @ConditionalOnClass、@ConditionalOnMissingBean、@ConditionalOnProperty 等,這些註解可以覆蓋大多數常見的條件化配置需求。
  • 使用條件化配置時,應注意避免建立複雜的條件邏輯,以保持配置的清晰和可維護性。

34. @ConditionalOnBean

條件註解,用於在容器中存在特定 Bean 的情況下才建立當前 Bean。這個註解通常用在基於 Spring Boot 的應用中,與自動配置(Auto-configuration)功能結合使用,以根據應用的配置和已存在的 Bean 來條件化地註冊新的 Bean。

使用

@ConditionalOnBean 註解可以應用於配置類中的 @Bean 方法上。當 Spring 容器中存在指定的 Bean 時,才會執行該方法並建立相應的 Bean。如果不存在指定的 Bean,則該方法會被忽略,不會建立任何 Bean。

屬性

有一個 RedisTemplate 的 Bean,並且你只想在 RedisTemplate 存在時才建立 RedisOperBean
@ConditionalOnBean 註解包含幾個屬性,用於指定條件細節:

  • value:Class<?>[] 型別,指定需要存在的 Bean 的型別。
  • type:String[] 型別,與 value 屬性類似,但允許使用 Bean 的名稱(而不是型別)。
  • annotation:Class<? extends Annotation>[] 型別,指定需要存在的 Bean 上必須擁有的註解型別。
  • name:String[] 型別,直接指定需要存在的 Bean 的名稱。
  • search:SearchStrategy 型別,用於指定搜尋 Bean 的策略,預設是 SearchStrategy.ALL,表示在所有的 Bean 定義中搜尋。

Demo

@Configuration  
public class RedisConfig {  
  
    @Bean  
    public RedisTemplate<String, Object> redisTemplate() {  
        // 配置 RedisTemplate ...  
        return redisTemplate;  
    }  
  
    @Bean  
    @ConditionalOnBean(name = "redisTemplate")  
    public RedisOperBean redisOperBean(RedisTemplate<String, Object> redisTemplate) {  
        // 假設 RedisOperBean 需要 RedisTemplate 作為依賴  
        return new RedisOperBean(redisTemplate);  
    }  
}

redisOperBean 方法上的 @ConditionalOnBean(name = "redisTemplate") 註解確保了只有當 redisTemplate Bean 存在時,redisOperBean 方法才會被執行,從而建立 RedisOperBean。

注意事項

  • @ConditionalOnBean 與其他條件註解(如 @ConditionalOnMissingBean、@ConditionalOnClass 等)一起構成了 Spring Boot 的條件化配置功能,提供了靈活的 Bean 載入控制。
  • 在使用 @ConditionalOnBean 時,需要注意 Bean 的載入順序。如果當前 Bean 依賴於其他尚未載入的 Bean,可能會導致意外的行為。
  • 儘量避免在應用中建立複雜的條件邏輯,以保持配置的清晰和可維護性。

相關文章