【问题标题】:Could we autowire an interface without any implementation in Spring?我们可以在 Spring 中自动装配一个没有任何实现的接口吗?
【发布时间】:2017-01-06 02:42:23
【问题描述】:

我们必须与合作伙伴共享我们的代码库以进行开发,但我们不想透露某些服务的实现。

假设我们有一个接口FooService 及其实现FooServiceImpl

public interface FooService
{
    void doSomething();
}

@Service
public class FooServiceImpl implements FooService
{
    @Override
    public String doSomething();
    {
        ...
    }
}

许多其他类自动装配此服务并调用 doSomething()。例如:

@Service
public class BarServiceImpl implements BarService
{
    @Autowired
    private FooService  fooService;

    @Override
    public String validate();
    {
        fooService.doSomething();
        ...
    }
}

如果我只是删除FooServiceImpl,当然会在启动时抛出NoSuchBeanException。如果我在自动连接 FooService 的任何地方都使用 @Autowired(required = false),那么每当调用 doSomething() 时,都会在运行时抛出 NullPointerException

除了手动删除 FooServiceImpl 中的每个方法体之外,还有其他方法可以解决这个问题吗?

感谢任何帮助。

【问题讨论】:

  • 您为什么要这样做?你需要一个FooService 才能让BarServiceImpl 工作,不是吗?
  • 您必须最终让他们实现。最好的情况是你可以编写一个存根实现。如果你没有配置一个真实的数据库,可以看看 Spring Boot 的数据源处理,看看它们是如何提供内存后备数据库的。

标签: java spring interface autowired interface-implementation


【解决方案1】:

我同意 chrylis 的观点;你的用例听起来你应该发布一个默认实现。我还将配置您的代码以允许您的库的用户提供他们自己的实现。 Spring 让您可以使用他们的 @Conditional... 注释轻松地做到这一点。具体来说,我认为你应该使用@ConditionalOnMissingBean

默认实现

@Component
public class DefaultFooServiceImpl implements FooService {
  @Override
  public void doSomething() {
    LOG.info("Using default implementation of doSomething(); nothing will happen");
  }
}

示例配置

@Configuration
public class ServiceConfig {
  @ConditionalOnMissingBean(FooService.class)
  @Bean
  DefaultFooServiceImpl defaultFooServiceImpl() {
    return new DefaultFooServiceImpl();
  }
}

当您的合作伙伴使用您的库时,他们会获得默认实施,以及提供更好实施的选项。当你使用你的库时,你可以创建一个ProprietaryFooServiceImpl bean,它会被注入。

【讨论】:

    【解决方案2】:

    我们可以在 Spring 中自动装配一个没有任何实现的接口吗?

    没有。

    您正在尝试为 接口创建实例,这在 Java 中是不可能的。

    【讨论】:

      【解决方案3】:

      首先,正如@AdrianShum 和@chrylis 评论的那样,您需要实现FooService 才能使BarServiceImpl.validate() 工作。所以不清楚你所说的“不想透露某些服务的实现”是什么意思。

      • NoSuchBeanException - 当您在 BarServiceImpl 中自动装配 FooService 时,将进行扫描以找到 FooService 类型的 bean。由于您没有任何FooService 的实现,因此会发生此错误。
      • NullPointerException - 如required=false,在初始化过程中忽略了上述问题。但是private FooService fooService 显然会有一个NULL 值。所以当你调用fooService.doSomething()时会发生异常。
      • 现在你可能会想,也许你可以把@Component(或类似的东西) 在您的interface 上。来自 Spring 文档,“此注释适用于 通过类路径自动检测的实现类 扫描”。然后会出现NoSuchBeanException,因为你没有 实现类。

      所以,你不能在 Spring 中没有任何实现的情况下自动装配接口。

      【讨论】:

        【解决方案4】:

        enter image description hereHi 抱歉回复晚了... 实际上最近我遇到了这个问题,这实际上是由于多个包。 这可以通过以下几个简单的点来解决。

        1. 创建spring项目时,项目必须只有一个主包。
        2. 当您需要不同的包时,您需要创建其他包作为主包的子包。
        3. 默认情况下,spring 将在运行时扫描主包。因此,如果您创建不同的包,spring 不会将这些包视为主包。
        4. 所以我们必须将所有其他包定义为子包,以解决所有这些类型的 @Autowired 和 bean 考虑问题...

        --->还有任何疑问请在下面命令...我会关注..

        【讨论】:

          猜你喜欢
          • 2020-11-15
          • 2017-05-11
          • 1970-01-01
          • 2019-01-16
          • 2019-02-22
          • 2012-03-30
          • 2012-10-05
          • 1970-01-01
          • 2017-05-25
          相关资源
          最近更新 更多