在 Java EE 和 CDI 中 select 根据存储在数据库中的配置值注入的实现是一个好习惯吗?
Is it a good practice in Java EE and CDI to select the implementatation to be injected based on the configuration value stored in the database?
我的任务是使用 JavaEE 7 重写 java 中数据库过程中存储的一些旧逻辑。该应用程序部署在 JBoss EAP 7 上。
有一项关键功能,因此我们需要某种切换器,以便能够在生产中的某些服务的新旧实现之间快速切换。
遗憾的是,即使出现严重问题,我们也无法立即交付和部署新版本。所以我们需要以数据库的形式引入这样的切换器table.
为了提供良好的可维护性,我想使用CDI注入old/new基于切换器的实现。
我看到的最简单的方法是利用 CDI Producers。在生产者方法中发出 DB-Request 是好的解决方案吗?
我的例子:
@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();
}
}
我真的不能对 "good practice" 问题发表评论,但你在这里有一个问题值得回答。
要完成你想做的事,你需要做以下一项,而不是两项:
- 确保
NewServiceOldImpl.class
和 NewServiceImpl.class
而不是 在他们的 bean types[=33= 集合中有 NewService
]
- 完全否决
NewServiceOldImpl.class
和 NewServiceImpl.class
否则,如果您尝试 @Inject
和 NewService
,将有两种可能性,并且在其他条件相同的情况下,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;
}
我的任务是使用 JavaEE 7 重写 java 中数据库过程中存储的一些旧逻辑。该应用程序部署在 JBoss EAP 7 上。
有一项关键功能,因此我们需要某种切换器,以便能够在生产中的某些服务的新旧实现之间快速切换。
遗憾的是,即使出现严重问题,我们也无法立即交付和部署新版本。所以我们需要以数据库的形式引入这样的切换器table.
为了提供良好的可维护性,我想使用CDI注入old/new基于切换器的实现。
我看到的最简单的方法是利用 CDI Producers。在生产者方法中发出 DB-Request 是好的解决方案吗?
我的例子:
@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();
}
}
我真的不能对 "good practice" 问题发表评论,但你在这里有一个问题值得回答。
要完成你想做的事,你需要做以下一项,而不是两项:
- 确保
NewServiceOldImpl.class
和NewServiceImpl.class
而不是 在他们的 bean types[=33= 集合中有NewService
] - 完全否决
NewServiceOldImpl.class
和NewServiceImpl.class
否则,如果您尝试 @Inject
和 NewService
,将有两种可能性,并且在其他条件相同的情况下,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;
}