」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 探索 Quarkus 中的合成豆。強大的擴充機制

探索 Quarkus 中的合成豆。強大的擴充機制

發佈於2024-09-02
瀏覽:608

Exploring Synthetic Beans in Quarkus. A Powerful Extension Mechanism

在 Quarkus 的世界里,依赖注入领域丰富且多才多艺,为开发人员提供了大量的工具来管理和控制 Bean。其中一种工具是合成豆的概念。合成 bean 是一种强大的扩展机制,允许您注册其属性不是从 Java 类、方法或字段派生的 bean。相反,合成 bean 的所有属性都由扩展定义。

在本文中,我们将深入了解 Quarkus 中的合成豆世界。我们将探讨合成豆的需求、它们的实际应用,以及如何在 Quarkus 应用程序中创建和使用它们。

了解合成豆

在 Quarkus 中,bean 是应用程序的构建块,由上下文和依赖注入 (CDI) 框架管理。通常,CDI bean 是使用各种 CDI 注释(例如 @ApplicationScoped、@RequestScoped 或 @Inject)进行注释的 Java 类。这些注释
允许CDI自动管理bean的生命周期和注入。

但是,在某些情况下,您可能需要注册一个不太适合传统 CDI 模型的 bean。这就是合成豆发挥作用的地方。合成 bean 由扩展创建,并且其属性完全由这些扩展定义。在常规 CDI 的世界中,您可以使用 AfterBeanDiscovery.addBean() 和 SyntheticComponents.addBean() 方法来实现此目的。在 Quarkus 中,这是使用 SyntheticBeanBuildItem 完成的。

什么时候需要合成豆?

那么,您什么时候可能需要在 Quarkus 中使用合成 bean?合成豆在以下情况下是一个强大的工具:

  1. 集成第三方库: 您正在使用没有 CDI 注释但需要集成到基于 CDI 的应用程序中的第三方库。合成豆可以帮助您弥补这一差距。

  2. 动态Bean注册:您需要在运行时动态注册bean,具体取决于配置或其他因素。合成 bean 使您可以灵活地动态创建和注册 bean。

  3. 定制 Bean 管理: 您需要对 Bean 的范围和行为进行细粒度控制,而这是标准 CDI 注释无法实现的。

  4. 实现专用 Bean: 您想要创建具有与传统 Java 类或方法不对应的独特属性的专用 Bean。

  5. 模拟测试依赖关系: 合成 bean 提供了一种有用的方法来模拟依赖关系并注入模拟实现以用于测试目的。

综合完成构建项

SynthesisFinishedBuildItem 用于指示 CDI bean 发现和注册过程已完成。这允许扩展知道何时可以安全地与已注册的 Bean 进行交互。

例如:

@BuildStep  
void onSynthesisFinished(SynthesisFinishedBuildItem synthesisFinished){
    // CDI bean registration is complete, can now safely interact with beans
    }

SyntheticBeansRuntimeInitBuildItem

SyntheticBeansRuntimeInitBuildItem 用于注册一个回调,该回调将在所有合成 bean 初始化后在运行时调用。如果您需要执行涉及合成 bean 的额外初始化逻辑,这非常有用。

例如:

@BuildStep
SyntheticBeansRuntimeInitBuildItem initSyntheticBeans(){

    return new SyntheticBeansRuntimeInitBuildItem(ids->{
    // Perform logic with initialized synthetic beans
    });

    }

传递给 SyntheticBeansRuntimeInitBuildItem 的回调将收到一个 Set,其中包含所有已初始化合成 bean 的 ID。

总之,SynthesisFinishedBuildItem 指示 bean 发现已完成,而 SyntheticBeansRuntimeInitBuildItem 允许根据合成 bean 初始化逻辑。

使用 SyntheticBeanBuildItem 创建合成 Bean

在 Quarkus 中,由于 SyntheticBeanBuildItem 类,创建合成 bean 是一个简单的过程。让我们逐步完成创建和使用合成 bean 的步骤:

  1. 创建合成 Bean 类: 首先定义合成 Bean 类。该类将成为您的合成豆的基础。
package com.iqnev;

public class MySyntheticBean {

  // Define the behavior and attributes of your synthetic bean
  public void printMessage() {
    System.out.println("Hello from synthetic bean!");
  }
}
  1. 创建 Quarkus 扩展: 您需要创建 Quarkus 扩展来注册您的合成 bean。该扩展类将使用 SyntheticBeanBuildItem 来配置您的 bean。

字节码生成方法

package com.iqnev;

import io.quarkus.arc.deployment.SyntheticBeanBuildItem;

public class MySyntheticBeanExtension {

  @BuildStep
  SyntheticBeanBuildItem syntheticBean() {
    return SyntheticBeanBuildItem
        .configure(MySyntheticBean.class)
        .scope(ApplicationScoped.class)
        .creator(mc -> {
          mc.returnValue(new MySyntheticBean());
        })
        .done();
  }
}

SyntheticBeanBuildItem 上的 .creator() 方法用于生成字节码,该字节码将在运行时创建合成 bean 的实例。

传递给 .creator() 的参数是 Consumer,它允许在方法内生成 Java 字节码。

在此示例中:

  1. mc 是 MethodCreator 实例
  2. mc.returnValue(new MySyntheticBean()) 生成字节码以创建 MySyntheticBean 的新实例并从方法返回它。

所以本质上,我们告诉 Quarkus 生成一个看起来像这样的方法:

MySyntheticBean createSyntheticBean(){
    return new MySyntheticBean();
    }

当需要注入或使用MySyntheticBean时,将调用这个生成的方法来实例化MySyntheticBean。

使用字节码生成的原因是合成bean与真实的Java类/方法不对应,因此我们必须显式生成一个方法来实例化它们

SyntheticBeanBuildItem 的输出是构建时记录的字节码。这限制了在运行时创建实例的方式。常见选项有:

  1. 直接通过.creator()生成字节码
  2. 使用 BeanCreator 子类
  3. 通过@Recorder方法生成实例

录音机方法

@Record 和 .runtimeValue() 方法是在 Quarkus 中为合成 bean 提供实例的替代方法。

这允许您通过用 @Record(STATIC_INIT) 注释的记录器类方法实例化合成 bean。

例如:

@Recorder
public class MyRecorder {

  @Record(STATIC_INIT)
  public MySyntheticBean createBean() {
    return new MySyntheticBean();
  }

}

  @BuildStep
  SyntheticBeanBuildItem syntheticBean(MyRecorder recorder) {
    return SyntheticBeanBuildItem
        .configure(MySyntheticBean.class)
        .runtimeValue(recorder.createBean());
  }

这里.runtimeValue()引用记录器方法来实例化bean。这允许直接传递 RuntimeValue 来提供合成 bean 实例。

例如:

@BuildStep 
SyntheticBeanBuildItem syntheticBean(){

    RuntimeValue bean= //...

    return SyntheticBeanBuildItem
    .configure(MySyntheticBean.class)
    .runtimeValue(bean);

    }

RuntimeValue 可以来自记录者、供应商、代理等。

总结一下:

  • @Record 是生成 RuntimeValue 的一种方法
  • .runtimeValue() 设置 SyntheticBeanBuildItem 上的 RuntimeValue

它们都实现了提供运行时实例的相同目标,只是方式略有不同。

当谈到为 Quarkus 中的合成 bean 提供运行时实例时,与直接生成字节码相比,我会考虑使用记录器(通过 @Record)作为更高级的方法
使用 .creator() 或提供简单的 RuntimeValues.

以下是使用录音机可以更高级的一些原因:

  • 更多封装-实例化bean的逻辑包含在单独的记录器类中,而不是直接包含在构建步骤中。这使得构建步骤变得精简。
  • 重用 - 记录器方法可以在多个合成 bean 之间重用,而不是重写创建者逻辑。
  • 运行时数据 - 记录器方法在运行时执行,因此它们可以利用运行时资源、配置、服务等来构造 bean。
  • 依赖注入 -记录器方法可以注入其他服务。
  • 生命周期控制 - 使用 @Record(STATIC_INIT) 或 @Record(RUNTIME_INIT) 注解的记录器方法可以更好地控制 bean 实例化生命周期。
  • 托管 bean - 在记录器内实例化的 Bean 本身可以是 CDI 托管 bean。

总而言之,记录器方法为实例化合成 bean 提供了更多的封装性、灵活性以及对运行时数据和服务的访问。与直接生成字节码相比,它们允许更高级的 bean 生产逻辑。

然而,对于记录器可能过度杀伤的简单情况,使用 .creator() 直接生成字节码仍然有用。但随着合成豆需求的增长,记录仪变得更加强大并且
高级方法。

可以在 Quarkus 中配置一个合成 bean 在 RUNTIME_INIT 阶段而不是默认的 STATIC_INIT 阶段进行初始化。

这是一个例子:

@BuildStep
@Record(RUNTIME_INIT)
SyntheticBeanBuildItem lazyBean(BeanRecorder recorder){

    return SyntheticBeanBuildItem
    .configure(MyLazyBean.class)
    .setRuntimeInit() // initialize during RUNTIME_INIT
    .runtimeValue(recorder.createLazyBean());

    }

要点是:

  • 在 SyntheticBeanBuildItem 上使用 setRuntimeInit() 将其标记为 RUNTIME_INIT
  • 记录器方法必须用@Record(RUNTIME_INIT)注解
  • 运行时 init 合成 bean 在 STATIC_INIT 期间无法访问

总之,对于不需要急切 STATIC_INIT 实例化的情况,可以在 RUNTIME_INIT 期间延迟初始化合成 bean。这可以优化启动时间。

使用合成 Bean: 现在您的合成 Bean 已注册,您可以在应用程序中注入并使用它。

package com.iqnev;

import javax.inject.Inject;

public class MyBeanUser {

  @Inject
  MySyntheticBean mySyntheticBean;

  public void useSyntheticBean() {
    // Use the synthetic bean in your code
    mySyntheticBean.printMessage();
  }
}

运行您的应用程序:照常构建并运行您的 Quarkus 应用程序,合成 bean 将可供注入和使用。

结论

Quarkus 中的合成 bean 提供了强大的机制,用于集成外部库、动态注册 bean 以及在基于 CDI 的应用程序中自定义 bean 行为。这些 bean 的属性是由扩展而不是 Java 类定义的,在管理依赖项方面提供了灵活性和多功能性。

正如我们在本文中探讨的那样,在 Quarkus 中创建和使用合成 bean 是一个简单的过程。通过利用 SyntheticBeanBuildItem 和 Quarkus 扩展,您可以无缝弥合传统 CDI 与更专业或动态 bean 注册要求之间的差距。

在不断发展的 Java 框架领域,Quarkus 通过提供合成 bean 等创新解决方案继续脱颖而出,使其成为现代、高效和灵活的应用程序开发的引人注目的选择。拥抱 Quarkus 中合成 bean 的强大功能,将您的依赖注入提升到一个新的水平!

版本聲明 本文轉載於:https://dev.to/yanev/exploring-synthetic-beans-in-quarkus-a-powerful-extension-mechanism-fbd?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 在 Hacktoberfest 中做出貢獻的新方式:直接在前端 AI
    在 Hacktoberfest 中做出貢獻的新方式:直接在前端 AI
    Hacktoberfest 又回來了,今年為開發者帶來了一種令人興奮的新參與方式。 您現在可以直接透過 Webcrumbs 平台上的 Frontend AI 建立和提交模板,而不是傳統的 GitHub Pull 請求。只需前往tools.webcrumbs.org,對模板進行編碼,然後在準備好後點擊...
    程式設計 發佈於2024-11-07
  • 為什麼使用不帶括號的函數指標時“cout”列印“1”?
    為什麼使用不帶括號的函數指標時“cout”列印“1”?
    為什麼「cout a function without call it (not f() but f;). Print 1 Always?」在此程式碼中,程式碼嘗試在不使用括號的情況下「呼叫」名為pr 的函數。然而,這實際上並不是呼叫該函數。相反,它將函數指標傳遞給 cout 函數。當函數指標隱式轉...
    程式設計 發佈於2024-11-07
  • 讓您的網頁更快
    讓您的網頁更快
    什么是 DOM?它吃什么? DOM(文档对象模型)是网页及其开发的基础。它是 HTML 和 XML 文档的编程接口,以树状对象表示文档的结构。有树枝和树叶。文档中的每个元素、属性和文本片段都成为该树中的一个节点。它允许 JavaScript 与 HTML 元素交互、修改它们或添加新...
    程式設計 發佈於2024-11-07
  • JavaScript 中的 require 與 import
    JavaScript 中的 require 與 import
    我記得當我開始編碼時,我會看到一些js檔案使用require()來匯入模組和其他檔案使用import。這總是讓我感到困惑,因為我並不真正理解其中的差異是什麼,或者為什麼專案之間存在不一致。如果您想知道同樣的事情,請繼續閱讀! 什麼是 CommonJS? CommonJS 是一組用於...
    程式設計 發佈於2024-11-07
  • 使用鏡像部署 Vite/React 應用程式:完整指南
    使用鏡像部署 Vite/React 應用程式:完整指南
    在 GitHub Pages 上部署 Vite/React 应用程序是一个令人兴奋的里程碑,但这个过程有时会带来意想不到的挑战,特别是在处理图像和资产时。这篇博文将引导您完成整个过程,从最初的部署到解决常见问题并找到有效的解决方案。 无论您是初学者还是有经验的人,本指南都将帮助您避免常见的陷阱,并...
    程式設計 發佈於2024-11-07
  • 我如何在我的 React 應用程式中優化 API 呼叫
    我如何在我的 React 應用程式中優化 API 呼叫
    作为 React 开发者,我们经常面临需要通过 API 同步多个快速状态变化的场景。对每一个微小的变化进行 API 调用可能效率低下,并且会给客户端和服务器带来负担。这就是去抖和巧妙的状态管理发挥作用的地方。在本文中,我们将构建一个自定义 React 钩子,通过合并有效负载和去抖 API 调用来捕获...
    程式設計 發佈於2024-11-07
  • 我們走吧!
    我們走吧!
    為什麼你需要嘗試 GO Go 是一種快速、輕量級、靜態類型的編譯語言,非常適合建立高效、可靠的應用程式。它的簡單性和簡潔的語法使其易於學習和使用,特別是對於新手來說。 Go 的突出功能包括內建的 goroutine 並發性、強大的標準庫以及用於程式碼格式化、測試和依賴管理的強大工具...
    程式設計 發佈於2024-11-06
  • 如何將 PNG 圖像編碼為 CSS 資料 URI 的 Base64?
    如何將 PNG 圖像編碼為 CSS 資料 URI 的 Base64?
    在CSS 資料URI 中對PNG 圖像使用Base64 編碼為了使用資料URI 將PNG 圖片嵌入到CSS 樣式表中,PNG資料必須先編碼為Base64 格式。此技術允許將外部圖像檔案直接包含在樣式表中。 Unix 命令列解決方案:base64 -i /path/to/image.png此指令將輸出...
    程式設計 發佈於2024-11-06
  • API 每小時資料的響應式 JavaScript 輪播
    API 每小時資料的響應式 JavaScript 輪播
    I almost mistook an incomplete solution for a finished one and moved on to work on other parts of my weather app! While working on the carousel that w...
    程式設計 發佈於2024-11-06
  • 用於 Web 開發的 PHP 和 JavaScript 之間的主要差異是什麼?
    用於 Web 開發的 PHP 和 JavaScript 之間的主要差異是什麼?
    PHP 與 JavaScript:伺服器端與客戶端 PHP 的作用與 JavaScript 不同。 PHP 運行在伺服器端。伺服器運行應用程式。除此之外,它還處理表單。當您提交表單時,PHP 會對其進行處理。另一方面,JavaScript 是客戶端的。它在瀏覽器中運行。它處理頁面互...
    程式設計 發佈於2024-11-06
  • 如何在 C++ 中迭代結構和類別成員以在運行時存取它們的名稱和值?
    如何在 C++ 中迭代結構和類別成員以在運行時存取它們的名稱和值?
    迭代結構體和類別成員在 C 中,可以迭代結構體或類別的成員來檢索它們的名稱和價值觀。以下是實現此目的的幾種方法:使用巨集REFLECTABLE 巨集可用於定義允許自省的結構。該巨集將結構體的成員定義為以逗號分隔的類型名稱對清單。例如:struct A { REFLECTABLE ( ...
    程式設計 發佈於2024-11-06
  • 如果需要準確答案,請避免浮動和雙精度
    如果需要準確答案,請避免浮動和雙精度
    float 和 double 問題: 專為科學和數學計算而設計,執行二元浮點運算。 不適合貨幣計算或需要精確答案的情況。 無法準確表示10的負次方,例如0.1,從而導致錯誤。 範例1: 減去美元金額時計算錯誤: System.out.println(1.03 - 0.42); // Resu...
    程式設計 發佈於2024-11-06
  • 在 Go 中使用 WebSocket 進行即時通信
    在 Go 中使用 WebSocket 進行即時通信
    构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要一种比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSoc...
    程式設計 發佈於2024-11-06
  • 如何在 Python 中使用代理程式運行 Selenium Webdriver?
    如何在 Python 中使用代理程式運行 Selenium Webdriver?
    使用Python 中的代理程式執行Selenium Webdriver當您嘗試將Selenium Webdriver 腳本匯出為Python 腳本並從命令列執行時,可能會遇到在使用代理的情況下出現錯誤。本文旨在解決此問題,提供使用代理有效運行腳本的解決方案。 代理整合要使用代理程式來執行 Selen...
    程式設計 發佈於2024-11-06
  • || 什麼時候運算子充當 JavaScript 中的預設運算子?
    || 什麼時候運算子充當 JavaScript 中的預設運算子?
    理解|| 的目的JavaScript 中非布林運算元的運算子在JavaScript 中,||運算子通常稱為邏輯OR 運算符,通常用於計算布林表達式。但是,您可能會遇到 || 的情況。運算符與非布林值一起使用。 在這種情況下,||運算子的行為類似於「預設」運算子。它不傳回布林值,而是根據某些規則傳回左...
    程式設計 發佈於2024-11-06

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

Copyright© 2022 湘ICP备2022001581号-3