首頁 > Java > java教程 > 主體

在 Spring Boot 中建立自訂註解的終極指南

PHPz
發布: 2024-08-25 18:01:02
原創
486 人瀏覽過

The Ultimate Guide to Create Custom Annotations in Spring Boot
這樣的註解充滿了 Spring Boot 中的整個專案。

但是你知道這些註解解決了什麼問題嗎?

為什麼要引入自訂註解?

如何建立自訂註解?

今天,我將介紹:

  • 為什麼要建立自訂註解?
  • 使用這些註解的主要好處是什麼?
  • 如何建立自訂註解?
  • 帶註解的方法是如何被呼叫的?
  • 何時使用自訂註解?
  • 什麼時候不應該使用自訂註解?
  • 使用自訂註解有哪些缺點?

?為什麼要建立自訂註解?

在 Spring Boot 中,註解不僅僅是添加元資料的一種方式。他們

  • 簡化複雜的任務
  • 減少樣板代碼
  • 增強程式碼可讀性

在 Spring 引入自訂註解之前,開發人員必須使用 XML 設定檔來管理電子郵件驗證等配置。

XML 設定將定義 bean、驗證器和其他必要的元件來執行驗證電子郵件地址等任務。

以下是如何在 Spring 應用程式中使用 XML 設定電子郵件驗證的範例:

The Ultimate Guide to Create Custom Annotations in Spring Boot

如您所見,這很容易成為一場噩夢,因為有數百個類,其中許多類相互依賴。

這也意味著開發人員每次必須新增新的依賴項時都必須尋找此 XML。

自訂註解的主要優點

簡化配置

Spring 引入了自訂註解來簡化配置,允許開發人員直接在程式碼中使用註解。

這減少了對大量 XML 配置的需求,使程式碼庫更乾淨且更易於維護。

支援聲明式編程

Spring 中的自訂註解啟用了聲明式方法。

開發者可以使用 @Transactional、@Cacheable 或 @Scheduled 等註解來聲明所需的行為,而無需編寫底層邏輯。

這會產生更具可讀性和可維護性的程式碼。

處理跨領域問題

Spring 的自訂註解通常與面向方面程式設計(AOP)一起使用,允許開發人員以集中的方式處理橫切關注點。

例如,@Transactional 註解可以跨多個方法或類別管理事務,而無需將事務管理邏輯分散在整個程式碼中。

減少樣板程式碼

它透過封裝常見行為減少了對樣板程式碼的需求。

例如,@Autowired 註解簡化了依賴注入,允許 Spring 自動注入依賴項,而不需要明確的建構子或 setter 方法

是否應該使用@Autowired 是不同的討論。

提高程式碼可讀性和一致性

透過將配置和橫切關注點抽象化為註解,Spring 提高了程式碼的可讀性。

您和您的同儕開發人員可以透過檢視方法或類別的註解來快速了解方法或類別的用途,並且註解有助於增強整個程式碼庫的一致性。

框架靈活性和可擴展性

自訂註釋可讓開發人員建立適合特定需求的註釋,從而以標準化的方式擴展框架的功能。

這種靈活性可幫助 Spring 在多個應用程式和架構中保持相關性和強大功能。

?如何建立自訂註釋

第 1 步:定義註釋

  • 透過定義介面建立新的註解。
  • 使用@interface來聲明它。
  • 新增元註解以指定註解的行為方式。
package co.officegeek.tokenratelimiter;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)  // Annotation available at runtime
@Target(ElementType.METHOD)          // Can be applied to methods
public @interface LogExecutionTime {
}
登入後複製
  • @Target:指示可以使用註解的位置(例如方法、類別)。
  • @Retention:指示註解保留多久(例如,執行時間、編譯時)。

步驟 2:建立一個面向來處理註釋

您可以使用 Spring 的 BeanPostProcessor、Aspect 或自訂註解處理邏輯來建立自訂邏輯來處理註解。

package co.officegeek.tokenratelimiter;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogExecutionTimeAspect {

    @Around("@annotation(LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;

        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}
登入後複製

第 3 步:應用註釋

將自訂註解套用到定義的方法、欄位或類別。

package co.officegeek.tokenratelimiter;

import org.springframework.stereotype.Service;

@Service
public class TestService {

    @LogExecutionTime
    public void serve() throws InterruptedException {
        // Simulate some work
        Thread.sleep(2000);
    }
}
登入後複製

How It Works:

  • The @LogExecutionTime annotation doesn't cause any method to be called directly.
  • The Spring AOP framework detects that a method has the @LogExecutionTime annotation using reflection.
  • The LogExecutionTimeAspect aspect is configured to apply around advice when a method with the @LogExecutionTime annotation is called.
  • The logExecutionTime method in the aspect is executed before and after the annotated method (serve), logging the execution time.

The Ultimate Guide to Create Custom Annotations in Spring Boot


How does the annotated method get invoked?

When you apply a custom annotation to a method, class, or field, the annotation itself doesn't directly cause any method to be called.

Instead, the logic associated with the annotation is typically implemented using reflection or aspect-oriented programming (AOP) in frameworks like Spring.

Here's a breakdown of how the compiler and runtime environment know what method to call when an annotation is applied:

1. Compile-Time Processing (Annotation Processors)

Some annotations are handled at compile time by annotation processors.

Java's javax.annotation.processing package allows developers to create custom annotation processors that generate code, validate annotations, or even modify the abstract syntax tree (AST) of the code being compiled.

The annotation processor reads the annotations during compilation and executes code based on those annotations.

This can include generating new classes or methods that the code will use later.

The @Override annotation is a compile-time annotation that doesn't invoke a method but instead tells the compiler to check if the method actually overrides a superclass method.

How It Works:

  • You define a custom annotation processor by extending AbstractProcessor and overriding the process method.
  • The processor will be invoked by the compiler when it encounters your annotation, allowing you to generate code or perform other tasks.

2. Runtime Processing (Reflection)

Custom annotations can be processed at runtime using reflection.

The runtime system (e.g., a framework like Spring) uses reflection to detect the presence of annotations on methods, classes, or fields, and then applies the corresponding behavior.

A custom annotation like @LogExecutionTime doesn't directly trigger any method call.

Instead, an aspect or some other reflective mechanism checks for the presence of the annotation at runtime and then wraps the method call with additional logic.

How It Works:

  • At runtime, you use Java's reflection API to check if a method or class has a specific annotation using methods like isAnnotationPresent.
  • Once detected, you can invoke methods or execute logic associated with that annotation.  For example, if a method has a @LogExecutionTime annotation, you might measure the time before and after the method call.

3. Aspect-Oriented Programming (AOP)

In frameworks like Spring, AOP is commonly used to handle custom annotations.

AOP allows you to define "aspects" that can intercept method calls and perform additional processing before or after the method execution.

When the AOP framework (e.g. Spring AOP) detects an annotation, it triggers the execution of an advice method associated with the aspect.

This advice method contains the logic that the AOP framework executes when the annotated method is called.

A @Transactional annotation in Spring doesn't execute any logic by itself.

Instead, the Spring framework's AOP infrastructure intercepts calls to methods annotated with @Transactional and wraps them with transaction management logic.

How It Works:

  • You define an aspect class with advice methods that are associated with specific pointcuts (join points where you want to apply the advice).
  • The aspect uses annotations like @Around or @Before to specify when the advice should be executed.
  • The AOP framework ensures that when a method with a custom annotation is called, the corresponding advice is executed automatically.

Use Cases Where Custom Annotations Are a Good Approach

Cross-Cutting Concerns

Custom annotations are ideal for handling cross-cutting concerns like logging, security, transaction management, and caching.

These are concerns that affect multiple parts of an application but are not related to the core business logic.

上面的@LogExecutionTime註解是一個很好的例子,因為它可以在所有方法中使用,而且它沒有任何業務邏輯。

聲明式程式設計

當您想要指定應該發生什麼而不是如何發生時,自訂註解提供了一種乾淨且富有表現力的方式來執行此操作。

@Cacheable 或 @Retry 等註解允許開發人員以宣告方式啟用快取或重試邏輯,而無需手動編寫實作程式碼。

框架或庫集成

自訂註解可以透過隱藏易於使用的註解背後的複雜性來簡化框架或程式庫的整合。

Spring 中的 @Autowired 這樣的註解有助於注入依賴項,而無需手動實例化它們。

複雜邏輯的封裝

當需要以可重複使用的方式封裝複雜邏輯時,自訂註解可以提供一個乾淨的 API 來套用此邏輯。

像@RateLimit這樣的註解可以封裝邏輯來限制方法被呼叫的次數,而不會用這個邏輯來擾亂方法的主體。

不應使用自訂註解的用例

簡單或一次性的邏輯

如果邏輯很簡單或只需要在單一位置應用,那麼建立自訂註解就太過分了,並且會使程式碼不必要地複雜化。

需要動態行為的邏輯

註解是在編譯時靜態定義的,不適合需要在執行時動態決定行為的場景。

如果方法的行為應根據使用者輸入或外部配置而改變,則使用自訂註解處理此問題可能會導致複雜的解決方案。

業務邏輯

核心業務邏輯不應抽象化為自訂註釋,因為這會使邏輯不那麼透明且難以維護。

使用@ProcessOrder這樣的註解來封裝業務流程可能會隱藏重要的業務規則,使程式碼更難理解和維護。

註解之間複雜的交互

如果行為依賴多個註釋之間的複雜交互,則可能會導致意外結果並使程式碼難以理解和調試。

組合影響相同方法的多個自訂註解(例如@Retry、@Cacheable、@LogExecutionTime)可能會導致不可預測的行為並且難以管理

效能關鍵程式碼

自訂註解通常依賴反射或代理機制,這可能會帶來效能開銷。

它們不應該用在程式碼的效能關鍵部分。

使用自訂註解向在緊密循環中呼叫數百萬次的方法新增日誌記錄可能會顯著降低效能。

?摘要 - 何時使用自訂註釋

自訂註解非常適合處理橫切問題,例如日誌記錄、安全性和事務管理。

它們也非常適合您需要在應用程式的多個部分應用相同行為的場景。

但是,對於簡單、一次性的邏輯,或需要細粒度控制和靈活性的情況,自訂註解可能不是最好的方法。

在決定實施之前考慮權衡。

?最後的想法

自訂註解是 Spring Boot 武器庫中的強大工具,但像任何工具一樣,應該謹慎使用它們。

它們提供了一種乾淨、可重複使用的方式來處理重複性任務並強制整個程式碼庫的一致性。

但請注意潛在的缺點,尤其是複雜性和性能方面。


??公告

我正在為軟體開發人員和有抱負的微服務架構師推出為期 10 天的隊列課程,介紹如何使用 Spring Boot 和 Bucket4j 設計和實現速率限制服務。

您將學到:

✅ 如何設計與建造可投入生產的微服務

✅ 深入了解速率限制演算法及其實現

✅ Spring Boot 開發、測試和容器化的最佳實踐

但這也是關於

✅ 將項目分解為具體任務

✅ 對自己負責

✅ 正確設計與建造專案

它針對的是想要設計和開發微服務的軟體開發人員,這是與大多數公司相關的用例。

特別適合那些處於軟體開發人員職業生涯早期的人,他們可能沒有“專案經驗”,但擁有大量的熱情和雄心。

如果您認為這對您有幫助,或者即使您只是想了解更多:

登記您的興趣,我會讓您知道研討會的詳細資訊。


這首先發佈在我的子堆疊上。訂閱我的 Substack - Weekend Developer 以第一時間取得更新。

您是需要對您所寫的程式碼提供回饋的開發人員嗎?

或您希望有人審查您的程式碼以便您做正確的事情?

我幫助人們進行免費的程式碼審查會議,以便他們能夠儘早獲得回饋並編寫更好的程式碼

在 Twitter (X) 或 LinkedIn 上私訊我,我將協助您編寫程式碼。

以上是在 Spring Boot 中建立自訂註解的終極指南的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!