1

I can't understand the difference between the annotation over the interface and the implementation. I've searched a lot of information it's not complete and it doesn't seem right to me. I decided to look into the question.

Consider

1 Variant.

Interface

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

Impl

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

And

 @Autowired
 private AuthenticationService authService;

Many sources, including stackoverflow, say that there are 2 key problems with this approach

  1. We create an unnecessary link to an external library (what library???)
  2. We may encounter NoSuchBeanDefinitionException (but for some reason there is no mention of @Qualifier or @Primary annotations or other ways)

2 Option

Interface

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

Impl

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

And

 @Autowired
 private InMemoryAuthenticationService authService;

In my practice, I always created an interface for the service and injected the interface. But now I've started to see the second option sometimes.

Questions.

Can you describe the pros and cons of both options in more detail? Does it even make sense to use the interfaces then, if they only have 1 implementation?

WBLord
  • 874
  • 6
  • 29
  • 1
    I saw this link https://stackoverflow.com/questions/16351780/where-should-service-annotation-be-kept-interface-or-implementation But I couldn't find an answer there. – WBLord Apr 11 '22 at 00:17
  • I think the key difference here is: do you want your implementation to be decided at compile time or run time? - Option 1, spring will attempt to find an unambiguous implementation at run-time. Option 2, you are specifying which implementation to inject. – Hopey One Apr 11 '22 at 00:55

1 Answers1

1

It is all in relation with two principal design : Open to extension closed to modification , and dependencies injection.

The main idea of Open closed from wekipedia : In object-oriented programming, the open–closed principle states "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification";[1] that is, such an entity can allow its behaviour to be extended without modifying its source code.

For the dependencies injection on spring , it is from Baeldung : Dependency Injection is a fundamental aspect of the Spring framework, through which the Spring container “injects” objects into other objects or “dependencies”. Simply put, this allows for loose coupling of components and moves the responsibility of managing components onto the container.

So as example , you have an application that read some data from an Oracle DataBase the implementation will be like that :

public interface ReadDataFromSource{
public abstract List<String> getData();
}

The implementation will be

@Service
public class ReadDataFromOracleDB implements ReadDataFromSource {
public List<String> getData(){
// code to read data from Oracle DB
}
}

For some reason the client need to change the implementation to read the data from a MysqlDataBase , the idea is to dont change the existen code ( closed to modification) , we should here add a new class that implements the same interface ReadDataFromSource :

@Service
public class ReadDataFromMysqlDB implements ReadDataFromSource {
public List<String> getData(){
// code to read data from Mysql DB
}
}

The call ( reference ) should be using the interface to garantee that the instance can be from any class that implements the interface. And like that we have the two version in our software , using Qualifiers or @primary , naming the beans and call using the names ; will inform the framework about any bean will be used in a given place . The first version (Oracle DB) still exist if we need to use it.

@Autowired
 private ReadDataFromSource dataReader;
Oussama ZAGHDOUD
  • 1,767
  • 5
  • 15
  • Thank you so much for the detailed answer. But do I need to create an interface at all if I have only 1 implementation and no more plans? For example, the classic Product Service or User Service imply only 1 implementation, but I often see interfaces for them – WBLord Apr 11 '22 at 08:06
  • Welcome , yes you can use class directly , but as best practice you shouldn't – Oussama ZAGHDOUD Apr 11 '22 at 09:05