Java中运行时的依赖注入

时间:2013-12-28 12:00:30

标签: java jsf cdi

我已经通过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

2 个答案:

答案 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服务器重新联机。