我已经通过Java CDI阅读了依赖功能,但到目前为止还无法弄清楚如何通过运行时注入一个类。让我先解释一下这个场景。
假设我有一个带有中央电子邮件服务的JSF网络应用程序。
我正在定义一个接口
public interface EmailService {
public String sendEmail(Email email);
}
接下来,我使用Smtp实现了EmailService的具体实现:
public class SmtpEmailServiceImpl implements EmailService {
@Override
public String sendEmail(Email email) {
// concrete implementation using Smtp
}
}
现在在我的网络应用程序中,我有一个JSF支持bean,应该注入EmailService以便发送电子邮件
public class JSFBackingBean {
// This is the EmailService to be injected
private EmailService emailService;
public String sendEmail(){
emailService.sendEmail(new Email());
}
}
现在假设Smtp-Server已关闭以进行维护。在这种情况下,我想将数据库中的所有电子邮件假脱机,并在Smtp服务器启动并运行时稍后处理它们。在这种情况下,我想有一个EmailService的第二个实现:
public class DatabaseEmailService implements EmailService {
@Override
public String sendEmail(Email email) {
// concrete implementation writing the email to a database
}
}
现在我从CDI了解到我可以使用Annotations注入正确的服务实现,但这意味着我必须重新构建和部署我的类,以防我想要更改适当的服务。有没有更好的解决方案,我可以使用,例如一个配置文件,以便在应用程序的运行时更改注入?
提前感谢您的回答 PRED
答案 0 :(得分:1)
在这种情况下,您可以编写自定义的Producer和Qualifier。而不是注入EmailService,例如注入“@Failsafe EmailService”。
然后写一个制作人
@Produces
@Failsafe
private EmailService failsafeEmailService() {
// here you can check if the Mail Server is available and then decide
// to return the "real" Service or the DB-Queue.
}
除了在方法体内创建/查找服务外,您还可以让CDI注入两个备选方案(直接或通过Instance<>),然后决定传播哪个。
@Produces
@Failsafe
private EmailService failsafeEmailService(MailServiceBean bean, DBQueue queue) {
return (check_if_mail_server_is_running) ? bean : queue
}
(当然DBQueue和Bean都必须实现EmailService)。
答案 1 :(得分:0)
嗯,我怀疑你是否想要这样做,以便这个电子邮件服务的每个客户都知道邮件服务需要被关闭,即使你使用了注释和实例选择器,例如:
@Inject
private Instance<EmailService> emailServiceInstance;
// few lines down
emailServiceInstance.select(new SmtpLiteral()).get();
你将如何以CDI的方式做到这一点。我建议的是,这个逻辑属于你的EmailService
,它本身会引入一个DB类的引用,该类将消息保存到数据库,直到SMTP服务器重新联机。