【问题标题】:Inject bean at runtime reading properties file在运行时注入 bean 读取属性文件
【发布时间】:2015-07-07 23:15:32
【问题描述】:

假设我有一个类MailConsoleService 和一个类MailSMTPService,它们都实现了MailService 接口。我有一个 EmailJob 类,它从数据库加载用户并通过 Spring 注入的 MailService 实例发送电子邮件。

我如何读取属性并在运行时确定要注入 MailService 的哪个实现?显然,这些属性可能会在应用程序运行时随时更改。

我考虑过创建一个工厂 bean,它将正确的实例从 spring 容器返回到 EmailJob,但我不知道如何实现。

注意:我所有的 bean 都配置为 Singleton 范围,所以我想我至少必须更改为 Prototype EmailJob

注意 2:在工厂 bean 中如何避免每次都读取属性文件?

谢谢!

【问题讨论】:

  • 您应该查看 Spring 的 @Conditional 注释,它可以让您轻松指定何时激活 bean 或配置类。 Spring Boot 提供了许多有用的实现,尤其是@ConditionalOnProperty

标签: java spring dependency-injection


【解决方案1】:

你可以这样做:

@Component
public class Factory {

@Autowired
private MailService mailConsoleService;

@Autowired
private MailService mailSmtpService;

@Value("${mailServiceProperty}")
private String mailServiceProperty;

public MailService getMailService() {
    switch (mailServiceProperty) {
    case "CONSOLE":
        return mailConsoleService;

    case "SMTP":
        return mailSmtpService;
    }       
    return null;
}

}

另外,您需要使用PropertyPlaceholderConfigurer 注入属性

【讨论】:

【解决方案2】:

我不确定我是否完全理解您的问题。但是根据我的理解,如果您想在运行时从属性文件中获取一个 bean,并且可以在运行时更改该文件,那么下面是执行此操作的一种方法。您需要一个应用上下文句柄并从属性文件中获取 bean 名称。

原型范围与此无关。如果您声明一个原型类型的 bean,则意味着您每次向应用程序上下文询问时都会获得一个新的 bean 实例。

@Component
public class EmailJob {  

    @Autowired
    private ApplicationContext appContext;

    public void sendEmail(){

        MailSender mailSender=(MailSender)appContext.getBean(<get bean name from properties file>);

        // do remaining things
    }


}

【讨论】:

  • 我知道这种方式,我不必改变这种方式的范围,但我怀疑这种方式是否正确。谢谢
  • 从纯粹的角度来看,应用上下文创建后不应该被使用。您创建应用程序上下文,它为您提供了起始 bean。从那时起,所有 bean 都应作为依赖项加载。您永远不应该使用应用程序上下文来获取 bean。但是如果你的属性会在应用运行的时候发生变化,那么上面是我能想到的唯一方法。
  • 我可以使用这个概念从 .drl 文件或 excel 文件中读取 drools 规则吗?
猜你喜欢
  • 1970-01-01
  • 2020-11-19
  • 2011-08-05
  • 2015-06-05
  • 1970-01-01
  • 2016-12-26
  • 1970-01-01
  • 2011-09-09
相关资源
最近更新 更多