在 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?合成豆在以下情况下是一个强大的工具:
集成第三方库: 您正在使用没有 CDI 注释但需要集成到基于 CDI 的应用程序中的第三方库。合成豆可以帮助您弥补这一差距。
动态Bean注册:您需要在运行时动态注册bean,具体取决于配置或其他因素。合成 bean 使您可以灵活地动态创建和注册 bean。
定制 Bean 管理: 您需要对 Bean 的范围和行为进行细粒度控制,而这是标准 CDI 注释无法实现的。
实现专用 Bean: 您想要创建具有与传统 Java 类或方法不对应的独特属性的专用 Bean。
模拟测试依赖关系: 合成 bean 提供了一种有用的方法来模拟依赖关系并注入模拟实现以用于测试目的。
SynthesisFinishedBuildItem 用于指示 CDI bean 发现和注册过程已完成。这允许扩展知道何时可以安全地与已注册的 Bean 进行交互。
例如:
@BuildStep void onSynthesisFinished(SynthesisFinishedBuildItem synthesisFinished){ // CDI bean registration is complete, can now safely interact with beans }
SyntheticBeansRuntimeInitBuildItem 用于注册一个回调,该回调将在所有合成 bean 初始化后在运行时调用。如果您需要执行涉及合成 bean 的额外初始化逻辑,这非常有用。
例如:
@BuildStep SyntheticBeansRuntimeInitBuildItem initSyntheticBeans(){ return new SyntheticBeansRuntimeInitBuildItem(ids->{ // Perform logic with initialized synthetic beans }); }
传递给 SyntheticBeansRuntimeInitBuildItem 的回调将收到一个 Set
总之,SynthesisFinishedBuildItem 指示 bean 发现已完成,而 SyntheticBeansRuntimeInitBuildItem 允许根据合成 bean 初始化逻辑。
在 Quarkus 中,由于 SyntheticBeanBuildItem 类,创建合成 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!"); } }
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
在此示例中:
所以本质上,我们告诉 Quarkus 生成一个看起来像这样的方法:
MySyntheticBean createSyntheticBean(){ return new MySyntheticBean(); }
当需要注入或使用MySyntheticBean时,将调用这个生成的方法来实例化MySyntheticBean。
使用字节码生成的原因是合成bean与真实的Java类/方法不对应,因此我们必须显式生成一个方法来实例化它们
SyntheticBeanBuildItem 的输出是构建时记录的字节码。这限制了在运行时创建实例的方式。常见选项有:
@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(){ RuntimeValuebean= //... return SyntheticBeanBuildItem .configure(MySyntheticBean.class) .runtimeValue(bean); }
RuntimeValue 可以来自记录者、供应商、代理等。
总结一下:
它们都实现了提供运行时实例的相同目标,只是方式略有不同。
当谈到为 Quarkus 中的合成 bean 提供运行时实例时,与直接生成字节码相比,我会考虑使用记录器(通过 @Record)作为更高级的方法
使用 .creator() 或提供简单的 RuntimeValues.
以下是使用录音机可以更高级的一些原因:
总而言之,记录器方法为实例化合成 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()); }
要点是:
总之,对于不需要急切 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 的强大功能,将您的依赖注入提升到一个新的水平!
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3