当前位置: 首页 > 面试题库 >

Spring:如何在运行时更改接口实现

蒋芷阳
2023-03-14
问题内容

作为Java开发人员,我经常需要在接口的不同实现之间进行选择。有时, 一次 只能进行 一次
选择,而另一些时候,我需要不同的实现来响应程序收到的不同输入。换句话说,我需要能够在运行时 更改
实现。这可以通过一个帮助器对象轻松实现,该对象将一些键(基于用户输入)转换为对适当接口实现的引用。

使用Spring,我可以将这样的对象设计为Bean,然后将其注入到需要的地方:

public class MyClass {

    @Autowired
    private MyHelper helper;

    public void someMethod(String someKey) {
        AnInterface i = helper.giveMeTheRightImplementation(someKey);
        i.doYourjob();
    }

}

现在,我应该如何实现助手?让我们从这个开始:

@Service
public class MyHelper {

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return new Foo();
        else if (key.equals("bar")) return new Bar();
        else ...
    }

}

这样的解决方案有几个缺陷。最糟糕的情况之一是,容器不知道从助手返回的实例,因此不能从依赖注入中受益。换句话说,即使我定义这样的Foo类:

@Service
public class Foo {

    @Autowired
    private VeryCoolService coolService;

    ...

}

Foo返回的实例MyHelper将没有coolService正确初始化该字段。

为避免这种情况,一个经常建议的解决方法是将 每个可能的实现 注入到助手中:

@Service
public class MyHelper {

    @Autowired
    private Foo foo;

    @Autowired
    private Bar bar;

    ...

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return foo;
        else if (key.equals("bar")) return bar;
        else ...
    }

}

但是我不是这种解决方案的忠实拥护者。我发现这样更优雅,更易于维护:

@Service
public class MyHelper {

    @Autowired
    private ApplicationContext app;

    public AnInterface giveMeTheRightImplementation(String key) {
        return (AnInterface) app.getBean(key);
    }

}

这基于Spring的ApplicationContext。

一个类似的解决方案是使用ServiceLocatorFactoryBean类:

public interface MyHelper {

    AnInterface giveMeTheRightImplementation(String key);

}

// Somewhere else, in Java config

@Bean
ServiceLocatorFactoryBean myHelper() {
    ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
    bean.setServiceLocatorInterface(MyHelper.class);
    return bean;
}

但是由于我不是Spring专家,所以我想知道是否还有更好的方法。


问题答案:

做您想要的事情的标准方法应该是:

interface YourInterface {
    void doSomething();
}

public class YourClass {

    @Inject @Any Instance<YourInterface> anImplementation;

    public void yourMethod(String someInput) {
        Annotation qualifier = turnInputIntoQualifier(someInput);
        anImplementation.select(qualifier).get().doSomething();
    }

    private Annotation turnInputIntoQualifier(String input) {
        ...
    }

}

当前,但是
Spring不支持它(尽管它计划用于v5.x)。它应该在应用程序服务器上工作 。

如果您想坚持使用Spring,那么ServiceLocatorFactoryBean基于解决方案的解决方案可能是最好的。



 类似资料:
  • 我需要在运行时更改与数据库的连接。例如,如果请求的参数是BD1,则连接数据库1,如果是BD2,则连接数据库2,等等。 我用的是Spring靴。最好的方法是什么。 我有这个,但不知道说我的存储库如何使用。

  • 问题内容: 我需要以固定的间隔运行批处理作业,并且能够在运行时更改此批处理作业的时间。为此,我遇到了Spring框架下提供的@Scheduled注释。但是我不确定如何在运行时更改fixedDelay的值。我进行了一些谷歌搜索,但没有发现任何有用的信息。 问题答案: 在spring启动中,你可以直接使用应用程序属性! 例如: 请注意,如果未定义属性,你还可以具有默认值,例如,默认值为“ 60”(秒)

  • 问题内容: 我需要在运行时在应用程序中更改属性。例如,我有一项服务,该服务发送带有重置密码的电子邮件。要求有效期为12小时。但是我想在运行时将此时间更改为24或更多。我需要给管理员执行此操作的机会。 我的财产文件有 我的服务 我的Spring xml配置 我可以在运行时以某种方式更改此值吗? 问题答案: 只需远离xml配置,就快要到2017年了。 使用@Value,您将从属性文件中获取hours.

  • 我已经使用SLF4j作为日志框架,由log4j支持。我的问题是,我正在寻找一种在运行时更改记录器日志记录级别的方法。 我知道slf4j不允许通过自己的API直接进行此操作,因此,我必须直接访问日志提供程序。就个人而言,我发现这是slf4j中的一个巨大缺陷。所以现在我的问题是,如何通过slf4j以编程方式确定我使用的是哪种提供者?使用slf4j的最大目的是让您变得与提供商无关-您可以轻松地在您喜欢的

  • 如何在运行时更改application.yaml的值?例如,我有一个服务器地址属性,希望在运行时更改