Можем ли мы автоматически связать интерфейс без какой-либо реализации в Spring?

Мы должны поделиться нашей кодовой базой с партнером для разработки, но мы не хотим раскрывать реализацию некоторых сервисов.

Скажем, у нас есть интерфейс 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. Если я использую @Autowired(required = false) везде, где FooService подключается автоматически, NullPointerException будет вызываться во время выполнения всякий раз, когда вызывается doSomething().

Помимо удаления тела каждого метода в FooServiceImpl вручную, есть ли другой способ обойти это?

Любая помощь приветствуется.


person Bruce    schedule 06.01.2017    source источник
comment
почему вы хотите это сделать? Вам нужен FooService для работы BarServiceImpl, не так ли?   -  person Adrian Shum    schedule 06.01.2017
comment
Вы должны предоставить им реализацию в конце концов. В лучшем случае вы можете написать реализацию заглушки. Можете взглянуть на обработку источников данных Spring Boot, чтобы увидеть, как они предоставляют резервную базу данных в памяти, если вы не настроите реальную.   -  person chrylis -cautiouslyoptimistic-    schedule 06.01.2017


Ответы (3)


Я согласен с 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();
  }
}

Когда ваш партнер использует вашу библиотеку, он получает реализацию по умолчанию, а также возможность предоставить лучшую реализацию. Когда вы используете свою библиотеку, вы можете создать bean-компонент ProprietaryFooServiceImpl, и вместо этого он будет внедрен.

person RustyTheBoyRobot    schedule 06.01.2017

Прежде всего, как прокомментировали @AdrianShum и @chrylis, вам нужна реализация FooService для работы BarServiceImpl.validate(). Так что неясно, что вы подразумеваете под "не хочу раскрывать реализацию некоторых сервисов".

  • NoSuchBeanException — при автоматическом подключении FooService к BarServiceImpl будет выполнено сканирование для поиска bean-компонента типа FooService. Поскольку у вас нет реализации FooService, возникает эта ошибка.
  • NullPointerException. Как и required=false, вышеуказанная проблема игнорируется во время инициализации. Но private FooService fooService будет иметь значение NULL, очевидно. Поэтому исключение возникает, когда вы вызываете fooService.doSomething().
  • Теперь вы можете подумать, может быть, вы можете поставить @Component (или что-то подобное) на свой interface. Из документации Spring: «Эта аннотация предназначена для автоматического обнаружения классов реализации посредством сканирования путей к классам». Тогда будет NoSuchBeanException, так как у вас нет классов реализации.

Таким образом, вы не можете автоматически подключить интерфейс без какой-либо реализации в Spring.

person Ramanujan R    schedule 06.01.2017

Можем ли мы автоматически связать интерфейс без какой-либо реализации в Spring?

Нет

Вы пытаетесь создать экземпляр для интерфейса, что невозможно в Java.

person Sundararaj Govindasamy    schedule 06.01.2017