196

I'm developing an application using Spring. I need to use the @Service annotation. I have ServiceI and ServiceImpl such that ServiceImpl implements ServiceI. I'm confused here as to where should I keep the @Service annotation.

Should I annotate the interface or the implementation with @Service? What are the differences between these two approaches?

TheKojuEffect
  • 20,103
  • 19
  • 89
  • 125
  • This is my answer to a similar post: https://stackoverflow.com/questions/38618995/need-of-dao-and-service-interfaces/48245959#48245959 – Agustí Sánchez Jan 14 '18 at 01:40

10 Answers10

220

I never put @Component (or @Service, ...) at an interface, because this make the interface useless. Let me explain why.

claim 1: If you have an interface then you want to use that interface for the injection point type.

claim 2: The purpose of an interface is that it define a contract that can been implemented by several implementations. On the other side you have your injection point (@Autowired). Having just one interface and only one class that implement it, is (IMHO) useless, and violates YAGNI.

fact: When you put:

  • @Component (or @Service, ...) at an interface,
  • have multiple classes that implements it,
  • at least two classes become Spring Beans, and
  • have an injection point that use the interface for type based injection,

then you will get and NoUniqueBeanDefinitionException (or you have a very special configurations setup, with Environment, Profiles or Qualifiers ...)

Conclusion: If you use @Component (or @Service, ...) at an interface then you must violate at least one of the two clains. Therefore I think it is not useful (except some rare scenarios) to put @Component at interface level.


Spring-Data-JPA Repository interfaces are something complete different

dazito
  • 7,740
  • 15
  • 75
  • 117
Ralph
  • 118,862
  • 56
  • 287
  • 383
  • 4
    It's very interesting what you write... so which is the right way? Is it not annotating the interface at all and giving the Service annotation to the implementations? Is Spring still capable of autowiring using the interface type? What is your answer to this> http://stackoverflow.com/questions/12899372/spring-why-do-we-autowire-the-interface-and-not-the-implemented-class/12899432#12899432 – corlaez Apr 21 '16 at 08:55
  • I agree with what I believe is your main point - that _most of the time_ it doesn't make sense to make your single responsibility service to implement an interface. But you seem to ignore that sometimes one *does* need a collection of services exposing the same contract (you recognize that it is technically possible, but you seems to believe that it is somehow "wrong" to do that). You should have considered that one can 1) inject a collection of services (so no `NoUniqueBenDefinitionException`) and 2) use `@Qualifier` to identify a specific service. – rsenna Feb 09 '17 at 13:33
  • 9
    I have a question, why do we need to create an interface for service layer when there is only one class implement it? I have seen many projects, they have **controller layer, **service layer** (**servicInterface**, **serviceInterfaceImpl**), and **repository layer**. – Yubaraj Mar 08 '17 at 10:54
  • 6
    @Yubaraj: fair point, but your question is about a quite other topic (for my answer I took the assumption: that there is a interface and the question is not about having the interface but about where to place the annotation). For your question: There is almost no reason to have a interface for a business service class that never will have two implementations. (BTW: As long as you are not building a api for some one else, you can always refactor you code and introduce the interface later on when you need it) – Ralph Mar 08 '17 at 11:21
  • @Ralph Yes, my question is different than your answer, but I think it is related to the original question that's why I asked. And I agree with your answer for both. Thank you. – Yubaraj Mar 09 '17 at 05:37
  • @Ralph This is the right ANSWER, I don't understand why another answer was accepted, actually accepted answer was incorrect and it violates the core idea of spring framework. Always code to the interface, and inject any implementation at runtime – Humoyun Ahmad Nov 01 '17 at 09:25
  • 2
    @Yubaraj , interfaces allow to make lightweight interface-based jdk proxies to beans when its needed. When there's no interface, spring has to do subclassing or modify beans using cglib to make a proxy. `@Transactional` is one of examples where a proxy to a bean is used. AOP is another one. – Yoory N. Nov 28 '17 at 08:35
  • 1
    Even though some times you won't have more than one implementing class, I still prefer declaring my methods in an interface. A fellow developer will find it easier to check what services are available only by looking at the declarations and documentation without worrying with the implementation. – HFSDev May 29 '19 at 17:53
  • @Yubaraj If you are following API first approach then in that case you need to prepare the API contract first (interface) by considering all the possibilities. Then you will hand it over to other developers to implement it. If you are building UI and API in parallel then not having interface in place can be the situation if you are not discussing much about the possibilities and just creating the solution based on what UI needs. – Sudhir Dhumal Oct 31 '19 at 16:15
  • Ralph is right about multiple implementations. But remember that some of the additional implementations may be generated, e.g. by mocking frameworks in unit tests. But proxies in various AOP schemes count as well. So, even if multiple implementations of an interface can't be found in your source tree, they may exist as ephemeral implementations at runtime. – Charlie Reitzel Jul 27 '21 at 21:14
  • I do not agree with what you said : "*Having just one interface and only one class that implement it, is (IMHO) useless, and violates YAGNI.*" for at least two reasons : - If you want to inject mocks, you need your code to depend on interfaces rather than implementations. - As Martin Fowler said in [this post](https://martinfowler.com/bliki/Yagni.html): Yagni only applies to capabilities built into the software to support a presumptive feature, it does not apply to effort to make the software easier to modify – Xavier KRESS Aug 24 '22 at 13:21
37

Basically annotations like @Service, @Repository, @Component, etc. they all serve the same purpose:

auto-detection when using annotation-based configuration and classpath scanning.

From my experience I am always using @Service annotation on the interfaces or abstract classes and annotations like @Component and @Repository for their implementation. @Component annotation I am using on those classes which serves basic purposes, simple Spring beans, nothing more. @Repository annotation I am using in the DAO layer, for e.g. if I have to communicate to the database, have some transactions, etc.

So I would suggest to annotate your interface with the @Service and other layers depending on the functionality.

Adam Siemion
  • 15,569
  • 7
  • 58
  • 92
Paulius Matulionis
  • 23,085
  • 22
  • 103
  • 143
  • 12
    Can you tell what are the differences between annotating interfaces and annotating implementations? – TheKojuEffect May 04 '13 at 02:54
  • 41
    From the [Spring docs](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Service.html), *"This annotation serves as a specialization of @Component, allowing for implementation classes to be autodetected through classpath scanning,"* suggesting that it's intended to be used on the implementation class. – nbrooks Jul 02 '15 at 13:24
  • 1
    @TheKojuEffect, This post explains in details difference between annotating interfaces vs implementations - http://stackoverflow.com/questions/3120143/where-should-i-put-transactional-annotation-at-an-interface-definition-or-at-a – Mahesh Feb 01 '17 at 06:56
  • 1
    @user3257644 Just note that the suggestions given by the answers in that post are in regards to the '@Transactional' annotation specifically, not all annotations in general. – Jonathan Feb 06 '17 at 06:29
  • 3
    The @service annotation on interfaces has no effect, just as the other stereotype annotations. All stereotype annotation should be put on either abstract or concrete classes. – bigfoot Mar 26 '17 at 02:27
  • @bigfoot to correct your statement, service annotation also doesn't work with abstract classes. Just with concrete classes. – chepaiytrath Jun 22 '18 at 13:50
21

I used @Component, @Service, @Controller and @Repository annotations only on the implementation classes and not on the interface. But @Autowired annotation with Interfaces still worked for me. If there's only one implementation of your interface Spring component scan automatically finds it with just @Autowired annotation. In case you have multiple implementations, you will need to use the @Qualifier annotation along with @Autowired to inject the correct implementation at the injection point.

yalkris
  • 2,596
  • 5
  • 31
  • 51
16

1. @Service on Interfaces

@Service
public interface AuthenticationService {

    boolean authenticate(String username, String password);
}

Normally, that's fine, but there's a drawback. By putting Spring's @Service on interfaces, we create an extra dependency and couple our interfaces with an outside library.

Next, to test the autodetection of our new service beans, let's create an implementation of our AuthenticationService:

public class InMemoryAuthenticationService implements AuthenticationService {

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

We should pay attention that our new implementation, InMemoryAuthenticationService, doesn't have the @Service annotation on it. We left @Service only on the interface, AuthenticationService.

So, let's run our Spring context with the help of a basic Spring Boot setup:

@SpringBootApplication
public class AuthApplication {

    @Autowired
    private AuthenticationService authService;

    public static void main(String[] args) {
        SpringApplication.run(AuthApplication.class, args);
    }
}

When we run our app, we may get the infamous NoSuchBeanDefinitionException, and the Spring context fails to start.

Therefore, placing @Service on interfaces isn't enough for the auto-detection of Spring components.


2. @Service on Abstract Classes

Using the @Service annotation on abstract classes isn't common.

We'll start by defining an abstract class from scratch and putting the @Service annotation on it:

@Service
public abstract class AbstractAuthenticationService {

    public boolean authenticate(String username, String password) {
        return false;
    }
}

Next, we extend AbstractAuthenticationService to create a concrete implementation without annotating it:

public class LdapAuthenticationService extends AbstractAuthenticationService {

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

Accordingly, we also update our AuthApplication, to inject the new service class:

@SpringBootApplication
public class AuthApplication {

    @Autowired
    private AbstractAuthenticationService authService;

    public static void main(String[] args) {
        SpringApplication.run(AuthApplication.class, args);
    }
}

After we run our AuthApplication, the Spring context doesn't start. It ends up with the same NoSuchBeanDefinitionException exception again.

So, using @Service annotation on abstract classes doesn't have any effect in Spring.


3. @Service on Concrete Classes

Contrary to what we've seen above, it's quite a common practice to annotate the implementation classes instead of abstract classes or interfaces.

In this way, our goal is mostly to tell Spring this class is going to be a @Component and mark it with a special stereotype, which is @Service in our case.

Therefore, Spring will autodetect those classes from the classpath and automatically define them as managed beans.

So, let's put @Service on our concrete service classes this time around. We'll have one class that implements our interface and a second that extends the abstract class that we defined previously:

@Service
public class InMemoryAuthenticationService implements AuthenticationService {

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

@Service
public class LdapAuthenticationService extends AbstractAuthenticationService {

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

We should take notice here that our AbstractAuthenticationService doesn't implement the AuthenticationService here. Hence, we can test them independently.

Finally, we add both of our service classes into the AuthApplication and give it a try:

@SpringBootApplication
public class AuthApplication {

    @Autowired
    private AuthenticationService inMemoryAuthService;

    @Autowired
    private AbstractAuthenticationService ldapAuthService;

    public static void main(String[] args) {
        SpringApplication.run(AuthApplication.class, args);
    }
}

Our final test gives us a successful result, and the Spring context boots up with no exceptions. Both of the services are automatically registered as beans.

You might have a look at this page for the other explanations.

Murat Yıldız
  • 11,299
  • 6
  • 63
  • 63
  • 3
    Thanks for your brilliant demonstration about the topic, right with the theoretical approach described in other interesting posts exposed here: It helps to get the necessary "click". – Lemmy_Caution Aug 06 '21 at 11:34
7

Pros of putting annotation on @Service is that it gives a hint that it is a service. I don't know if any implementing class will by default inherit this annoation.

Con side is that you are coupling your interface with a specific framework i.e. Spring, by using spring specific annotation. As interfaces are supposed to be decoupled from implementation, I would not suggest using any framework specific Annotations or object part of your interface.

  • 1
    I think we've all heard the strong coupling argument multiple times, but remember that annotations can be present without the jar, so basically as long as your coupling is on annotations it can still be decoupled. – Niels Bech Nielsen Jul 01 '14 at 06:12
7

I would put @Service on your class but put the name of the interface as a parameter to the annotation e.g.

interface ServiceOne {}

@Service("ServiceOne")
class ServiceOneImpl implements ServiceOne{}

By doing that you get all the benefits and can still inject the interface but get the class

@Autowired 
private ServiceOne serviceOne;

So your interface is not tied to spring framework and you can change the class at any time and not have to update all your injection points.

So if I wanted to change the implementation class I could just annotate the new class and remove from the first but that's all that is required to be changed. If you inject the class you could have a lot of work when ever you want to change the impl class.

Sampada
  • 2,931
  • 7
  • 27
  • 39
user1239403
  • 71
  • 1
  • 1
2

One benefit of spring is to easily switch Service (or other) implementation. For this, you need to annotate on the interface and declare variable like this :

@Autowired
private MyInterface myVariable;

and not :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

Like the first case, you can activate which implementation to inject from the moment it is unique (only one class implements the interface). In the second case, you need to refactor all your code (the new class implementation has another name). As a consequence, the annotation needs to be on the interface as much as possible. Furthermore, JDK proxies are well suited for this : they are created and instantiated at application startup because runtime type is known by advance, contrary to CGlib proxies.

François F.
  • 229
  • 2
  • 17
  • 6
    "MyClassImplementationWhichImplementsMyInterface" LOL – inafalcao Nov 05 '18 at 07:54
  • 1
    You don't need to annotate on the interface for the first example to work. You can annotate with `@Service` an implementation and autowire the interface. Spring will check for any object implementing this interface. – Marco Oct 26 '19 at 06:19
0
interface MyService {}

@Service
class MyServiceImpl implements MyService{}

@Autowired 
private MyService myService;

My testing result on spring-boot 2.7.4 is:

Adding @Service ONLY to interface doesn't create spring bean named MyService. It will error on Autowired.

@Service will need to be added to implementation class to create bean com.*.service.impl.MyServiceImpl $$EnhancerBySpringCGLIB$$9140ae19 Spring will wire it to private MyService myService;

Abe
  • 310
  • 3
  • 15
-3

There are 5 annotations which could be used for making spring beans. List in below of answers.

Do you really need an interface? If you are going to have one implementation for each service interface, just avoid it, use only class. Of course, if you don't have RMI or when interface proxy is required.

@Repository - use for injecting your dao layer classes.

@Service - use for injecting your service layer classes. In service layer also you might need to use @Transactional annotation for db transaction management.

@Controller - use for your frontend layer controllers, such as JSF managed beans injecting as spring beans.

@RestController - use for spring rest controllers, this would help you to avoid every time to put @ResponseBody and @RequestBody annotations in your rest methods.

@Component - use it in any other case when you need to Inject spring bean which is not controller, service, or dao class

  • Yes, you need an interface on borders of your layers (like data access layer and service layer). They enable loose coupling of modules that contain those layers implementations. Without them, the clients of mentioned layers have to know concrete types and you need to change them when you, say, want to decorate your BasicDao with CachingDao... – Igand Mar 21 '18 at 15:03
-4

To put it simply:

@Service is a Stereotype annotation for the service layer.

@Repos­itory is a Stereotype annotation for the persis­tence layer.

@Component is a generic stereotype annotation used to tell Spring to create an instance of the object in the Appl­ication Context. It's possible to define any name for the instance, the default is the class name as camel case.

Graham
  • 7,431
  • 18
  • 59
  • 84
HughParker
  • 25
  • 4
  • 5
    Meaning of these annotations isn't being seeked but WHERE to put them on Interface or its implementation. – nanosoft Jun 28 '18 at 14:19