Spring. Разница между аннотацией над интерфейсом и реализацией

Не могу понять в чём разница между аннотацией над интерфейсом и реализацией. Я много искал информации она не полная и мне кажется она не верная. Решил разобраться в вопросе.

Рассмотрим

1 Вариант

Интерфейс

    @Service
    public interface AuthenticationService {
    
        boolean authenticate(String username, String password);
    }

Реализация

    public class InMemoryAuthenticationService implements AuthenticationService {
    
        @Override
        public boolean authenticate(String username, String password) {
            //...
        }
    }

И далее

 @Autowired
 private AuthenticationService authService;

Во многих источниках, в том числе и stackoverflow говорится, что при таком подходе есть 2 ключевые проблемы

  1. Мы создаём лишнюю связь с внешней библиотекой (какой библиотекой???)
  2. Мы можем столкнуться с NoSuchBeanDefinitionException (но почему-то нигде не говориться о аннотациях @Qualifier или @Primary и прочих способах)

2 Вариант

Интерфейс

    public interface AuthenticationService {
    
        boolean authenticate(String username, String password);
    }

Реализация

    @Service
    public class InMemoryAuthenticationService implements AuthenticationService {
    
        @Override
        public boolean authenticate(String username, String password) {
            //...
        }
    }

И далее

 @Autowired
 private InMemoryAuthenticationService authService;

В моей практике я всегда создавал интерфейс для сервиса и инжектил интерфейс. Но сейчас стал иногда наблюдать и второй вариант.

Вопросы

Можете более подробно описать плюсы и минусы обоих вариантов? Имеет ли смысл вообще тогда использовать интерфейсы, если у них всего 1 имплементация?


Ответы (1 шт):

Автор решения: ulxanxv

Разница в многом.

Ты хочешь создать свой собственный класс от интерфейса. Зачем в самом интерфейсе ставить Spring-аннотацию, тем самым запрещая создавать класс от этого интерфейса не помещая его в контекст Spring? А если я не хочу, чтобы данный класс был бином?

Проблема в том, что разработчик должен сам решать, что будет делать данный класс.

Могу привести пример с обработкой исключений.

Вы разрабатываете библиотеку и в коде у вас есть место, которое может выбросить RuntimeException. Вопрос: нужно его обрабатывать или пробрасывать дальше? Ответ: пробрасывать дальше.

Если вы обработаете данное исключение в своей библиотеке, то потом, когда другой разработчик будет писать логику пользуясь вашей библиотекой он уже не сможет определить своё собственное поведение для возникшей ситуации, потому что ВЫ его уже определили и запретили как-то менять. Думаю, объяснил доступно.

Правильно делать вот так:

Интерфейс

public interface AuthenticationService {

    boolean authenticate(String username, String password);

}

Реализация

@Service
public class InMemoryAuthenticationService implements AuthenticationService {

    @Override
    public boolean authenticate(String username, String password) {
        //...
    }

}

Использование

@Autowired
private AuthenticationService authService;
→ Ссылка