首頁 >Java >java教程 >探索 Quarkus 中的合成豆。強大的擴充機制

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

PHPz
PHPz原創
2024-08-30 06:02:32398瀏覽

Exploring Synthetic Beans in Quarkus. A Powerful Extension Mechanism

在 Quarkus 的世界中,依賴注入領域豐富且用途廣泛,為開發人員提供了大量管理和控制 Bean 的工具。其中一種工具是合成豆的概念。合成 bean 是一種強大的擴充機制,可讓您註冊其屬性不是從 Java 類別、方法或欄位派生的 bean。相反,合成 bean 的所有屬性都由擴展定義。

在本文中,我們將深入了解 Quarkus 中的合成豆世界。我們將探討合成 bean 的需求、它們的實際應用,以及如何在 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 中,建立合成 bean 是一個簡單的過程,這要歸功於 SyntheticBeanBuildItem 類別。讓我們逐步完成建立和使用合成 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 is the MethodCreator instance
  2. mc.returnValue(new MySyntheticBean()) generates the bytecode to create a new instance of MySyntheticBean and return it from the method.

So essentially, we are telling Quarkus to generate a method that looks something like:

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

This generated method will then be called to instantiate the MySyntheticBean when it needs to be injected or used.

The reason bytecode generation is used is that synthetic beans do not correspond to real Java classes/methods, so we have to explicitly generate a method to instantiate them

The output of SyntheticBeanBuildItem is bytecode recorded at build time. This limits how instances are created at runtime. Common options are:

  1. Generate bytecode directly via .creator()
  2. Use a BeanCreator subclass
  3. Produce instance via @Recorder method

Recorder Approach

The @Record and .runtimeValue() approaches are alternate ways of providing instances for synthetic beans in Quarkus.

This allows you to instantiate the synthetic bean via a recorder class method annotated with @Record(STATIC_INIT).

For example:

@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());
  }

Here the .runtimeValue() references the recorder method to instantiate the bean. This allows passing a RuntimeValue directly to provide the synthetic bean instance.

For example:

@BuildStep 
SyntheticBeanBuildItem syntheticBean(){

    RuntimeValue<MySyntheticBean> bean= //...

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

    }

The RuntimeValue could come from a recorder, supplier, proxy etc.

So in summary:

  • @Record is one approach to generate the RuntimeValue
  • .runtimeValue() sets the RuntimeValue on the SyntheticBeanBuildItem

They both achieve the same goal of providing a runtime instance, just in slightly different ways.

When it comes to providing runtime instances for synthetic beans in Quarkus, I would consider using recorders (via @Record) to be a more advanced approach compared to directly generating bytecode
with .creator() or supplying simple RuntimeValues.

Here are some reasons why using recorders can be more advanced:

  • More encapsulation - The logic to instantiate beans is contained in a separate recorder class rather than directly in build steps. This keeps build steps lean.
  • Reuse - Recorder methods can be reused across multiple synthetic beans rather than rewriting creator logic.
  • Runtime data - Recorder methods execute at runtime so they can leverage runtime resources, configs, services etc. to construct beans.
  • Dependency injection - Recorder methods can inject other services.
  • Life cycle control - Recorder methods annotated with @Record(STATIC_INIT) or @Record(RUNTIME_INIT) give more control over bean instantiation life cycle.
  • Managed beans - Beans instantiated inside recorders can themselves be CDI managed beans.

So in summary, recorder methods provide more encapsulation, flexibility and access to runtime data and services for instantiating synthetic beans. They allow for more advanced bean production logic compared to direct bytecode generation.

However, direct bytecode generation with .creator() can still be useful for simple cases where recorders may be overkill. But as synthetic bean needs grow, recorders are a more powerful and
advanced approach.

It is possible to configure a synthetic bean in Quarkus to be initialized during the RUNTIME_INIT phase instead of the default STATIC_INIT phase.

Here is an example:

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

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

    }

The key points are:

  • Use setRuntimeInit() on the SyntheticBeanBuildItem to mark it for RUNTIME_INIT
  • The recorder method must be annotated with @Record(RUNTIME_INIT)
  • The runtime init synthetic beans cannot be accessed during STATIC_INIT

So in summary, synthetic beans can be initialized lazily during RUNTIME_INIT for cases where eager STATIC_INIT instantiation is not needed. This allows optimizing startup time.

Use the Synthetic Bean: Now that your synthetic bean is registered, you can inject and use it in your application.

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

Running Your Application: Build and run your Quarkus application as usual, and the synthetic bean will be available for injection and use.

Conclusion

Synthetic beans in Quarkus provide a powerful mechanism for integrating external libraries, dynamically registering beans, and customizing bean behavior in your CDI-based applications. These beans, whose attributes are defined by extensions rather than Java classes, offer flexibility and versatility in managing dependencies.

正如我們在本文中探討的那樣,在 Quarkus 中創建和使用合成 bean 是一個簡單的過程。透過利用 SyntheticBeanBuildItem 和 Quarkus 擴展,您可以無縫地彌合傳統 CDI 與更專業或動態 bean 註冊要求之間的差距。

在不斷發展的 Java 框架領域,Quarkus 透過提供合成 Bean 等創新解決方案繼續脫穎而出,使其成為現代、高效和靈活的應用程式開發的引人注目的選擇。擁抱 Quarkus 中合成 bean 的強大功能,將您的依賴注入提升到一個新的水平!

以上是探索 Quarkus 中的合成豆。強大的擴充機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn