为什么 @Specializes 注释没有取代我的 bean?

问题描述 投票:0回答:1

我们有一个 java EE 应用程序,它有一个核心模块和一些其他模块。核心模块中存在一个调度程序,声明如下:

@Singleton
@Transactional
@RunAs("admintask")
@RunAsPrincipal("CreateDataScheduler")
public class CreateDataScheduler

但是在我们运行的模块中,我们想用另一个调度程序替换这个调度程序,这样 CreateDataScheduler 根本不运行,只运行 CreateDataScheduler。我怎样才能做到这一点?我尝试使用 @Specializes 注释,但是两个调度程序都被调用。

@Singleton
@Transactional
@RunAs("admintask")
@RunAsPrincipal("CreateDataScheduler")
@Specializes   //annotated
public class CreateDataSchedulerTEST extends CreateDataScheduler

我也将其作为替代方案放入 beans.xml 文件中,但出现错误: 启用的替代类 CreateDataSchedulerTEST 与任何 bean 不匹配,或者未使用 @Alternative 或 @Alternative 构造型进行注释,或者未声明使用 @Alternative 或 @Alternative 构造型进行注释的生产者”

正确的做法是什么?

jakarta-ee cdi
1个回答
0
投票

我假设这些模块处于不同的部署中(EAR/WAR)。

正如我们在评论中讨论的,这里的问题是用

@Schedule
注释的方法是由 EJB 容器处理的。因此,尝试通过 CDI 覆盖它是没有意义的 - 即使包含该方法的 EJB 也是 CDI bean。

然而,对此有一个优雅的解决方案,假设两个调度相同(例如每 30 分钟一次),并且第二个模块与核心模块处于不同的部署中(2 个不同的 WAR/EAR 文件):

仅保留 1 个

@Singleton
EJB,即核心模块中的 EJB。让它依赖于 CDI 组件,调度程序方法只需委托给 CDI 组件,其中包含所有实际逻辑。在仅在第二次部署中部署的其他模块中,按照您在问题中描述的方式专门化 CDI 组件。现在,第二个部署的调度程序将选择专用程序组件。

示例代码:

// Core module
@Singleton
@Transactional
@RunAs("admintask")
@RunAsPrincipal("CreateDataScheduler")
public class CreateDataScheduler {
  @Inject SchedulingLogic schedulingLogic;

  @Schedule(hour = "*", minute = "*/30", persistent = false)
  public void start() {
    schedulingLogic.start();
  }
}

/**
 * This is the CDI component that contains the scheduling logic
 * in the core module.
 */
@ApplicationScoped
public class SchedulingLogic {
  public void start() {
    // do stuff...
  }
}

在第二个模块中:

/**
 * This is the CDI component that contains the specialized
 * scheduling logic of the second module.
 */
@ApplicationScoped
@Specializes
public class SchedulingLogicTEST extends SchedulingLogic {
  public void start() {
    // do stuff specific to the second module...
  }
}

如果时间安排不一样,可能需要多花些力气,但原理是一样的。只需使用 EJB 规范支持的编程式调度,而不是声明式调度。

IMO CDI 非常强大,比 EJB 强大得多。这也是一个更通用的解决方案,例如适用于独立的“SE”应用程序,而不仅仅是“EE”应用程序。我相信以环境中立的方式编写应用程序和业务逻辑是一个好主意,CDI 可以帮助实现这一点。像

CreateDataScheduler
这样的组件是从特定环境(在本例中:知道如何调度作业的 EJB 容器)到与环境无关的业务逻辑的适配器。如果这个逻辑需要独立运行,例如从 SE 应用程序中,添加例如Quartz 调度程序,甚至是调用相同逻辑的内置
ScheduledExecutorService
/
ScheduledThreadPoolExecutor
。 (帮助你的逻辑保持环境中立的另一件事是构造函数注入 - 这样组件可以直接使用
new
实例化,并且在 SE 情况下你甚至不需要 CDI、Spring 等;但那是另一个故事了)

© www.soinside.com 2019 - 2024. All rights reserved.