【问题标题】:Interface to concrete class conditional instantiation in SpringSpring中具体类条件实例化的接口
【发布时间】:2023-03-05 10:08:01
【问题描述】:

我有一个基于 Spring 的 Java 应用程序,其中许多类使用以下自动装配接口。它们在所有地方都使用这个接口。

@Autowired
private IOperatingSystemManager m_operatingSystemManager;

目前,该接口只有一种实现方式如下:

@Component
public class WindowsManager implements IOperatingSystemManager 
{
 // Windows based shenanigans
}

应用程序按预期工作。春天是快乐的。每个人都很高兴。 好吧,不是每个人...

所以,我想添加另一个IOperatingSystemManager 的具体实现..

@Component
public class LinuxManager implements IOperatingSystemManager 
{
 // Linux based shenanigans
}

我们想要的是根据属性文件设置有条件地自动连接 IOperatingSystemManager。 (比如说.. os=windows.. 基本上是一个任意字符串,不能从系统属性等派生出来,因为这是一个虚拟示例。实际的管理器与操作系统无关。)

我不想更改任何已自动连接到接口并在接口外工作的类。我所需要的只是让 Spring 查看一些逻辑,这些逻辑将指示变量的自动装配并为以下各项连接正确的具体实例:

@Autowired
IOperatingSystemManager m_operatingSystemManager 

在无数个地方。

文档和网络搜索谈论配置文件、条件、bean 工厂、限定符等。但我们不想使用配置文件;和限定符似乎需要更改所有接口变量注释。

工厂方法看起来很有前途,但对 Spring 来说是新手,找不到明确的答案。

实现此目的的简单且推荐的方法是什么?

【问题讨论】:

  • 你应该看看弹簧配置文件
  • 为什么不想使用配置文件?它们将是显而易见的解决方案......使用一些自制啤酒很可能是个坏主意。在维护代码时,这将更容易出错且更难理解。
  • @TobiasKremer 感谢您的评论。我们已经有预定义的配置文件,用于控制连接字符串等,我们不想为此引入新的配置文件。至少不是首选。我同意我们不想要自制解决方案。如果没有其他更简单的自然解决方案行之有效,那么我们将试一试个人资料。

标签: java spring pojo


【解决方案1】:

不是扫描WindowsManager 类,而是创建一个实现IOperatingSystemManager 接口的具体实例或另一个,具体取决于您的逻辑条件。

首先,从WindowsManager 类中删除@Component 注释。

然后,创建并扫描这个 @Configuration 类,它将充当您的 bean 的工厂:

@Configuration
public class OperatingSystemManagerFactory {

    @Bean
    public IOperatingSystemManager getOperatingSystemManager() {
        if ( /* some logic that evaluates to true if windows */ ) {
            return new WindowsManager();
        } else {
            // Linux default option ;)
            return new LinuxManager();
        }
    }
}

使用此解决方案,您无需更新任何引用 IOperatingSystemManager 接口的类。

【讨论】:

  • Federico,我是否需要做任何其他事情来引导这个配置类,以便 spring 知道这一点? (xml或用组件等注释)
  • @rajanadar 不,@Configuration 就足够了,它是一个 Spring 注释,例如 @Component。你可以扫描它。
  • 当我运行所有测试时,工厂代码被调用并且一些测试通过了。但是其中很多都失败了,因为 spring 似乎正在研究其中一个具体类(OperatingSystemManager.class)以获取对 IOperatingSystemManager 的引用,这些引用在许多类中自动装配为构造函数参数。不知道为什么 Spring 不查看该 bean 的工厂方法,而是查看没有自动装配或组件注释的具体类?
  • 这是一个确切的例外。通过构造函数参数表达的不满足依赖关系,索引为 1 类型 [com.company.IOSManager]: : 创建文件 [D:\ dev\Build\com.company\build\com\company\OSManager.class]:bean 的实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 bean 类 [com.company.OSManager]:未找到默认构造函数;嵌套异常是 java.lang.NoSuchMethodException: com.company.OSManager.();我的具体类被命名为 OSManager 和 LinuxOSManager
  • 感谢费德里科。问题是我们的单元测试为 OSManager 设置了组件扫描上下文过滤器,而我没有将表达式更改为这个新的 bean 工厂类。改变它,解决了所有问题。非常感谢您的帮助 Federico。
【解决方案2】:

我不知道你使用的是哪个版本的 spring,但你可以选择这个

http://www.intertech.com/Blog/spring-4-conditional-bean-configuration/

在这里,如您所见,您可以根据您可以决定的条件创建一个 bean。它实际上给出了你的例子,Windows 和 Linux :),所以我相信这就是你要找的。​​p>

编辑:

如果你使用的是spring-boot,你还有一些其他的条件注解

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html#boot-features-condition-annotations

【讨论】:

  • 感谢 Gokhan。我使用了下面 Federico 扩展的配置选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 2016-07-18
相关资源
最近更新 更多