在Java EE和CDI中,根据数据库中存储的配置值选择要注入的实现是否是一种良好的做法



我有一项任务,使用JavaEE7,用java重写存储在数据库过程中的一些旧逻辑。该应用程序部署在JBoss EAP7上。

有一个关键功能,因此我们需要有某种切换器,以便能够在生产中快速切换一些服务的新旧实现。

不幸的是,即使出现关键问题,我们也无法立即交付和部署新版本。所以我们需要以数据库表的形式引入这样的切换器。

为了提供良好的可维护性,我想使用CDI来注入基于切换器的旧/新实现。

我认为最简单的方法是利用CDI Producers。在Producer方法中发出DB请求是一个好的解决方案吗?

我的例子:

@ApplicationScoped
public class NewServiceProducer {
@Inject
private ImplementationSwitcherDAO implementationSwitcherDAO;
@Produces
@RequestScoped
public NewService produceNewService(){
//a DB-Call is done here        
boolean useOldVersion = implementationSwitcherDAO.isUseOldVersionForService("NewService");
if(useOldVersion){
return CDI.current().select(NewServiceOldImpl.class).get();
}
return CDI.current().select(NewServiceImpl.class).get();
}
}

我真的不能对"良好实践"问题发表评论,但你有一个问题值得回答。

要做你想做的事,你需要做以下其中一项,但不能同时做两项:

  1. 确保NewServiceOldImpl.classNewServiceImpl.class在它们的bean类型集中没有NewService
  2. 完全否决NewServiceOldImpl.classNewServiceImpl.class

否则,如果您尝试@InjectNewService,将有两种可能性,并且在其他条件相同的情况下,CDI将以某种AmbiguousResolutionException失败。

我会这样实现你的解决方案:

// Let's assume that NewServiceImpl is a regular managed bean
@RequestScoped
@Typed({ NewServiceImpl.class, Object.class }) // ...or whatever, but not NewService.class
public class NewServiceImpl { /*...*/ }
// Let's assume that NewServiceOldImpl is a regular managed bean
@RequestScoped
@Typed({ NewServiceOldImpl.class, Object.class }) // ...or whatever, but not NewService.class
public class NewServiceOldImpl { /*...*/ }
// Then somewhere else:
@Produces
@RequestScoped
private static NewService produceNewService(final NewServiceOldImpl oldImpl,
final NewServiceImpl newImpl) {
if (implementationSwitcherDAO.isUseOldVersionForService("NewService")) {
return oldImpl;
}
return newImpl;
}

相关内容

最新更新