Java中运行时的依赖项InjeAction

Java中运行时的依赖项InjeAction,java,jsf,cdi,Java,Jsf,Cdi,我已经通过JavaCDI阅读了依赖性功能,但到目前为止还不知道如何通过运行时注入类。让我先解释一下情况 假设我有一个JSFWeb应用程序和一个中央电子邮件服务 我正在定义一个接口 public interface EmailService { public String sendEmail(Email email); } 接下来,我将使用Smtp具体实现EmailService: public class SmtpEmailServiceImpl implements EmailServic

我已经通过JavaCDI阅读了依赖性功能,但到目前为止还不知道如何通过运行时注入类。让我先解释一下情况

假设我有一个JSFWeb应用程序和一个中央电子邮件服务

我正在定义一个接口

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
    }

}
现在在我的web应用程序中,我有了一个JSF支持bean,它应该注入EmailService以便发送电子邮件

public class JSFBackingBean {
    // This is the EmailService to be injected
    private EmailService emailService;


    public String sendEmail(){
    emailService.sendEmail(new Email());
    }
}
现在让我们假设Smtp服务器因维护而停机。在这种情况下,我想假脱机数据库中的所有电子邮件,并在Smtp服务器启动并运行后处理它们。在这种情况下,我希望第二次实现EmailService:

public class DatabaseEmailService implements EmailService {

@Override
    public String sendEmail(Email email) {
    // concrete implementation writing the email to a database
    }

}
现在我从CDI了解到,我可以使用注释来注入适当的服务实现,但这意味着我必须重新构建和部署我的类,以防我想要更改适当的服务。是否有更好的解决方案,例如使用配置文件,以便在应用程序运行时更改注入

提前谢谢你的回答
Pred

好吧,我怀疑您是否希望这样做,以便此电子邮件服务的每个客户端都知道需要关闭邮件服务,即使您使用了注释和实例选择器,例如:

@Inject
private Instance<EmailService> emailServiceInstance;

// few lines down

emailServiceInstance.select(new SmtpLiteral()).get();
@Inject
私有实例;
//几行
emailServiceInstance.select(新的SmtpLiteral()).get();

这就是你用CDI方式做的。我建议的是,此逻辑属于您的
电子邮件服务
,并且它本身会注入对某个DB类的引用,该DB类将消息持久保存到数据库,直到SMTP服务器重新联机。

在这种情况下,您可以编写自定义生产者和限定符。不要注入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(直接或通过实例)注入两个备选方案,然后决定传播哪一个,而不是在方法体中创建/查找服务

@Produces
@Failsafe
private EmailService failsafeEmailService(MailServiceBean bean, DBQueue queue) {
   return (check_if_mail_server_is_running) ? bean : queue
}

(当然,DBQueue和Bean都必须实现EmailService)。

我的想法是向客户机隐藏邮件服务器是否已启动并正在运行。我想做的是,例如,在维护期间更改配置文件以插入DBEmailService而不是SmtpEmailService,并且在Smtp服务器启动并运行后将其更改回SmtpEmailService。客户不会知道邮件服务的技术细节。比如说,我有一个SAP后端,可以从web应用程序下订单。如果SAP因维护而停机,我希望切换到另一个服务实现来缓存传入订单,而不进行重建和depl。我的webappWell,你正在重新启动你的应用程序。我会在这个EmailService中加入操作逻辑,只让您的客户端注入EmailService。谢谢,不一定需要重新启动。如果我使用spring,这将是配置xml中的一个简单更改。难道没有更优雅的方式吗?假设我正在提供一个可以处理数据库或LDAP身份验证的软件。我希望我的客户在安装过程中选择他希望使用的身份验证类型。这需要通过配置屏幕动态地进行,而不是通过构建和部署classesAgreed。CDI不是春天。CDI中最接近您的东西是备选方案,它需要放在beans.xml中。