」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 在 Spring Boot 中建立自訂註解的終極指南

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

發佈於2024-11-05
瀏覽:627

The Ultimate Guide to Create Custom Annotations in Spring Boot
Such annotations fill the entire project in Spring Boot.

But do you know what problems these annotations solve?

Why were custom annotations introduced to begin with?

How to create custom annotations?

Today, I will cover:

  • Why create custom annotations?
  • What are the key benefits of using these annotations?
  • How to create custom annotations?
  • How does the annotated method get invoked?
  • When to use custom annotations?
  • When not to use custom annotations?
  • What are the disadvantages of using custom annotations?

? Why Create Custom Annotations?

In Spring Boot, annotations are more than just a way to add metadata. They

  • Simplify complex tasks
  • Reduce boiler-plate code
  • Enhance code-readability

Before Spring introduced custom annotations, developers had to manage configurations like email validation using XML configuration files.

The XML configuration would define beans, validators, and other necessary components to perform tasks such as validating email addresses.

Here's an example of how email validation might have been configured using XML in a Spring application:

The Ultimate Guide to Create Custom Annotations in Spring Boot

As you can see, this can easily become a nightmare where there are hundreds of classes with many of them relying on each other.

It also meant a developer had to go look up this XML every time they had to add a new dependency.

Key Benefits of Custom Annotations

Simplification of Configuration

Spring introduced custom annotations to simplify configuration by allowing developers to use annotations directly in their code.

This reduced the need for extensive XML configuration, making the codebase cleaner and easier to maintain.

Support for Declarative Programming

Custom annotations in Spring enable a declarative approach.

Developers can use annotations like @Transactional, @Cacheable, or @Scheduled to declare desired behaviors without writing the underlying logic.

This results in more readable and maintainable code.

Handling Cross-Cutting Concerns

Spring's custom annotations, often used with Aspect-Oriented Programming (AOP), allow developers to handle cross-cutting concerns in a centralized manner.

For example, the @Transactional annotation manages transactions across multiple methods or classes without scattering transaction management logic throughout the code.

Reducing Boilerplate Code

It reduces the need for boilerplate code by encapsulating common behaviours.

For instance, the @Autowired annotation simplifies dependency injection, allowing Spring to automatically inject dependencies, rather than requiring explicit constructor or setter methods

It is a different discussion whether you should be using @Autowired or not.

Improving Code Readability and Consistency

By abstracting configuration and cross-cutting concerns into annotations, Spring improves the readability of the code.

You and your peer developers can quickly understand the purpose of a method or class by looking at its annotations, and annotations help enforce consistency across the codebase.

Framework Flexibility and Extensibility

Custom annotations allow developers to create their annotations tailored to specific needs, thus extending the framework's functionality in a standardized way.

This flexibility has helped Spring remain relevant and powerful across multiple applications and architectures.

? How to Create a Custom Annotation

Step 1: Define the Annotation

  • Create a new annotation by defining an interface.
  • Use @interface to declare it.
  • Add meta-annotations to specify how the annotation should behave.
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: Indicates where the annotation can be used (e.g., methods, classes).
  • @Retention: Indicates how long the annotation is retained (e.g., runtime, compile-time).

Step 2: Create an Aspect to Handle the Annotation

You can create a custom logic to process the annotation using Spring's BeanPostProcessor, Aspect, or custom annotation processing logic.

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;
    }
}

Step 3: Apply the Annotation

Apply your custom annotation to methods, fields, or classes as defined.

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.

The @LogExecutionTime annotation above is a good example as that can be used across all the methods and it does not have any business logic.

Declarative Programming

When you want to specify what should happen rather than how it should happen, custom annotations provide a clean and expressive way to do this.

Annotations like @Cacheable or @Retry allow developers to enable caching or retry logic declaratively, without writing the implementation code manually.

Framework or Library Integration

Custom annotations can simplify the integration of frameworks or libraries by hiding the complexity behind an easy-to-use annotation.

Annotations like @Autowired in Spring help in injecting dependencies without having to manually instantiate them.

Encapsulation of Complex Logic

When complex logic needs to be encapsulated in a reusable way, custom annotations can provide a clean API for applying this logic.

An annotation like @RateLimit could encapsulate logic to limit the number of times a method can be called, without cluttering the method's body with this logic.

Use Cases Where Custom Annotations Should Not Be Used

Simple or One-Off Logic

If the logic is simple or only needs to be applied in a single place, creating a custom annotation is overkill and can unnecessarily complicate the code.

Logic That Requires Dynamic Behavior

Annotations are statically defined at compile-time, making them unsuitable for scenarios where behaviour needs to be dynamically determined at runtime.

If a method's behaviour should change based on user input or external configuration, handling this with custom annotations can lead to complex solutions.

Business Logic

Core business logic should not be abstracted into custom annotations, as this can make the logic less transparent and harder to maintain.

Using an annotation to encapsulate a business process like @ProcessOrder might hide important business rules, making the code harder to understand and maintain.

Complex Interactions Between Annotations

If the behavior depends on complex interactions between multiple annotations, it can lead to unexpected results and make the code difficult to understand and debug.

Combining multiple custom annotations that affect the same method (e.g., @Retry, @Cacheable, @LogExecutionTime) can result in unpredictable behavior and is difficult to manage

Performance-Critical Code

Custom annotations often rely on reflection or proxy mechanisms, which can introduce performance overhead.

They should not be used in performance-critical sections of code.

Using a custom annotation to add logging to a method that is called millions of times in a tight loop could significantly degrade performance.

? Summary - When to Use Custom Annotations

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

They're also great for scenarios where you need to apply the same behaviour across multiple parts of your application.

However, for simple, one-off logic, or where fine-grained control and flexibility are required, custom annotations might not be the best approach.

Consider the trade-offs before you decide to implement them.

? Final Thoughts

Custom annotations are a powerful tool in your Spring Boot arsenal, but like any tool, they should be used judiciously.

They offer a clean, reusable way to handle repetitive tasks and enforce consistency across your codebase.

But be mindful of the potential downsides, especially for complexity and performance.


?? Announcement

I am launching a 10-day cohort-based course for software developers and aspiring microservices architects on designing and implementing rate-limiting service using Spring Boot and Bucket4j.

You'll learn:

✅ How to design and build a production-ready microservice

✅ In-depth knowledge of rate-limiting algorithms and their implementation

✅ Best practices in Spring Boot development, testing, and containerisation

But it is also about

✅ breaking down the project into specific tasks

✅ Being accountable to yourself

✅ Designing and Building the project right

It is targeted at software developers who want to design and develop a microservice which is a use case relevant to most companies.

It's ESPECIALLY for those earlier in their software developer career who might not have "project experience" but tons of passion and ambition.

If this is something that you think will help you or even if you are just curious to know more:

Register your interest and I will let you know the workshop details.


This was first published on my Substack. Subscribe to my Substack - Weekend Developer to get updates first.

Are you a developer who needs feedback on the code you write?

Or do you want someone to review your code so that you are doing the right things?

I help people with free code review sessions so that they can get early feedback and write better code

DM me on Twitter (X) or on LinkedIn and I will help you with your code.

版本聲明 本文轉載於:https://dev.to/dishitdevasia/the-ultimate-guide-to-create-custom-annotations-in-spring-boot-fpa?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 破解編碼面試的熱門必備書籍(從初級到高級排名)
    破解編碼面試的熱門必備書籍(從初級到高級排名)
    准备编码面试可能是一个充满挑战的旅程,但拥有正确的资源可以让一切变得不同。无论您是从算法开始的初学者、专注于系统设计的中级开发人员,还是完善编码实践的高级工程师,这份按难度排名的前 10 本书列表都将为您提供成功所需的知识和技能。你的软件工程面试。这些书籍涵盖了从基本算法到系统设计和简洁编码原则的所...
    程式設計 發佈於2024-11-06
  • Java 字串實習初學者指南
    Java 字串實習初學者指南
    Java String Interning 引入了透過在共享池中儲存唯一字串來優化記憶體的概念,減少重複物件。它解釋了 Java 如何自動實習字串文字以及開發人員如何使用 intern() 方法手動將字串新增至池中。 透過掌握字串駐留,您可以提高 Java 應用程式的效能和記憶體效率。要深入了解...
    程式設計 發佈於2024-11-06
  • 如何在 GUI 應用程式中的不同頁面之間共用變數資料?
    如何在 GUI 應用程式中的不同頁面之間共用變數資料?
    如何從類別中取得變數資料在 GUI 程式設計環境中,單一應用程式視窗中包含多個頁面是很常見的。每個頁面可能包含各種小部件,例如輸入欄位、按鈕或標籤。當與這些小部件互動時,使用者提供輸入或做出需要在不同頁面之間共享的選擇。這就提出瞭如何從一個類別存取另一個類別的變數資料的問題,特別是當這些類別代表不同...
    程式設計 發佈於2024-11-06
  • React 中的動態路由
    React 中的動態路由
    React 中的動態路由可讓您基於動態資料或參數建立路由,從而在應用程式中實現更靈活、更強大的導航。這對於需要根據使用者輸入或其他動態因素呈現不同元件的應用程式特別有用。 使用 React Router 設定動態路由 您通常會使用react-router-dom程式庫在React中實作動態路由。這...
    程式設計 發佈於2024-11-06
  • 大批
    大批
    方法是可以在物件上呼叫的 fns 數組是對象,因此它們在 JS 中也有方法。 slice(begin):將陣列的一部分提取到新數組中,而不改變原始數組。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index ...
    程式設計 發佈於2024-11-06
  • WPF中延遲操作時如何避免UI凍結?
    WPF中延遲操作時如何避免UI凍結?
    WPF 中的延遲操作WPF 中的延遲操作對於增強用戶體驗和確保平滑過渡至關重要。常見的情況是在導航到新視窗之前添加延遲。 為了實現此目的,經常使用 Thread.Sleep,如提供的程式碼片段所示。但是,在延遲過程中,使用 Thread.Sleep 阻塞 UI 執行緒會導致 UI 無回應。這表現為在...
    程式設計 發佈於2024-11-06
  • 利用 Java 進行即時資料流和處理
    利用 Java 進行即時資料流和處理
    In today's data-driven world, the ability to process and analyze data in real-time is crucial for businesses to make informed decisions swiftly. Java...
    程式設計 發佈於2024-11-06
  • 如何修復損壞的 InnoDB 表?
    如何修復損壞的 InnoDB 表?
    從 InnoDB 表損壞中恢復災難性事件可能會導致資料庫表嚴重損壞,特別是 InnoDB 表。遇到這種情況時,了解可用的修復選項就變得至關重要。 InnoDB Table Corruption Symptoms查詢中所述的症狀,包括交易日誌中的時間戳錯誤InnoDB 表的修復策略雖然已經有修復MyI...
    程式設計 發佈於2024-11-06
  • JavaScript 陣列和物件中是否正式允許使用尾隨逗號?
    JavaScript 陣列和物件中是否正式允許使用尾隨逗號?
    陣列與物件中的尾隨逗號:標準還是容忍? 數組和物件中尾隨逗號的存在引發了一些關於它們的爭論JavaScript 的標準化。這個問題源自於在不同瀏覽器中觀察到的不一致行為,特別是舊版的 Internet Explorer。 規範狀態規範狀態ObjectLiteral : { } { P...
    程式設計 發佈於2024-11-06
  • 最佳引導模板產生器
    最佳引導模板產生器
    在當今快速發展的數位環境中,速度和效率是關鍵,網頁設計師和開發人員越來越依賴 Bootstrap 建構器來簡化他們的工作流程。這些工具可以快速創建響應靈敏、具有視覺吸引力的網站,使團隊能夠比以往更快地將他們的想法變為現實。 Bootstrap 建構器真正改變了網站的建構方式,使過程更加易於存取和高...
    程式設計 發佈於2024-11-06
  • 簡化 NestJS 中的檔案上傳:無需磁碟儲存即可高效能記憶體中解析 CSV 和 XLSX
    簡化 NestJS 中的檔案上傳:無需磁碟儲存即可高效能記憶體中解析 CSV 和 XLSX
    Effortless File Parsing in NestJS: Manage CSV and XLSX Uploads in Memory for Speed, Security, and Scalability Introduction Handling file uploa...
    程式設計 發佈於2024-11-06
  • 使用 SubDomainRadar.io 和 Python 輕鬆發現隱藏子網域
    使用 SubDomainRadar.io 和 Python 輕鬆發現隱藏子網域
    作為網路安全專業人員、漏洞賞金獵人或滲透測試人員,發現隱藏的子域對於識別至關重要域中的潛在漏洞。子網域通常託管可能容易受到攻擊的被遺忘的服務或測試環境。 在這篇文章中,我將向您介紹SubDomainRadar.io 及其Python API 包裝器 — 自動化子域枚舉的終極工具和安全工作流程中的反...
    程式設計 發佈於2024-11-06
  • Python 中的 HackerRank 問題 - 基本資料類型列表
    Python 中的 HackerRank 問題 - 基本資料類型列表
    此 Python 程式碼旨在根據使用者提供的命令對清單執行一系列操作。讓我們一步步分析程式碼,了解其工作原理: if __name__ == '__main__': N = int(input()) l = [] while(N>0): cmd_l = ...
    程式設計 發佈於2024-11-06
  • ust-Know 進階 Tailwind CSS 實用程式可增強開發體驗
    ust-Know 進階 Tailwind CSS 實用程式可增強開發體驗
    Tailwind CSS 以其實用性優先的方法而聞名,使開發人員能夠直接在 HTML 中創建高度可自訂的設計。除了基礎知識之外,掌握進階實用程式還可以顯著增強您的開發工作流程,使其更快、更有效率。在這裡,我們將探索每個開發人員都應該知道的六個高級 Tailwind CSS 實用程序,並透過並排程式碼...
    程式設計 發佈於2024-11-06
  • Qt Signals 中的 DirectConnection 與 QueuedConnection:何時該選擇哪一個?
    Qt Signals 中的 DirectConnection 與 QueuedConnection:何時該選擇哪一個?
    Qt 訊號:深入研究 DirectConnection 和 QueuedConnectionQt 訊號在 Qt 應用程式中元件之間的通訊中發揮著至關重要的作用。然而,選擇 DirectConnection 和 QueuedConnection 作為連線方法可能會產生重大影響,尤其是在處理多執行緒應用...
    程式設計 發佈於2024-11-06

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3