205 votes

Où doit-on conserver l'annotation @Service ? Interface ou implémentation ?

Je suis en train de développer une application en utilisant Spring. J'ai besoin d'utiliser le @Service annotation. J'ai ServiceI y ServiceImpl tal que ServiceImpl implements ServiceI . Je suis confus quant à l'endroit où je dois garder le @Service annotation.

Devrais-je annoter l'interface ou l'implémentation avec @Service ? Quelles sont les différences entre ces deux approches ?

226voto

Ralph Points 42744

Je n'ai jamais mis @Component (ou @Service ...) à une interface, car cela rend l'interface inutile. Je vais vous expliquer pourquoi.

revendication 1 : Si vous avez une interface, vous voulez utiliser cette interface pour le type de point d'injection.

revendication 2 : Le but d'une interface est de définir un contrat qui peut être mis en œuvre par plusieurs implémentations. De l'autre côté, vous avez votre point d'injection ( @Autowired ). Avoir une seule interface et une seule classe qui l'implémente, est (IMHO) inutile, et viole YAGNI .

fait : Quand tu mets :

  • @Component (ou @Service ...) à une interface,
  • ont plusieurs classes qui l'implémentent,
  • au moins deux classes deviennent des Spring Beans, et
  • ont un point d'injection qui utilise l'interface pour l'injection basée sur le type,

alors vous obtiendrez et NoUniqueBeanDefinitionException (ou vous avez une configuration très spéciale, avec un environnement, des profils ou des qualificatifs...)

Conclusion : Si vous utilisez @Component (ou @Service ...) à une interface, alors vous devez violer au moins l'une des deux clauses. C'est pourquoi je pense qu'il n'est pas utile (à l'exception de quelques rares scénarios) de mettre @Component au niveau de l'interface.


Les interfaces Spring-Data-JPA Repository sont complètement différentes.

37voto

Paulius Matulionis Points 6868

Fondamentalement, les annotations comme @Service , @Repository , @Composant etc., ils ont tous le même objectif :

l'autodétection lors de l'utilisation de la configuration basée sur les annotations et de l'analyse du classpath. d'analyse.

D'après mon expérience, j'utilise toujours @Service sur les interfaces ou les classes abstraites et des annotations telles que @Component y @Repository pour leur mise en œuvre. @Component que j'utilise sur ces classes qui servent des objectifs de base, de simples beans de Spring, rien de plus. @Repository que j'utilise dans le DAO par exemple, si je dois communiquer avec la base de données, effectuer des transactions, etc.

Je vous suggère donc d'annoter votre interface avec la balise @Service et d'autres couches en fonction de la fonctionnalité.

23voto

anonymous_123 Points 127

Utilicé @Component , @Service , @Controller y @Repository uniquement sur les classes d'implémentation et non sur l'interface. Mais @Autowired avec Interfaces fonctionne toujours pour moi. S'il n'y a qu'une seule implémentation de votre interface, Spring component scan la trouve automatiquement avec juste @Autowired annotation. Si vous avez plusieurs implémentations, vous devrez utiliser l'annotation @Qualifier avec l'annotation @Autowired pour injecter l'implémentation correcte au point d'injection.

19voto

Murat Yıldız Points 1829

1. @Service sur les interfaces

@Service
public interface AuthenticationService {

    boolean authenticate(String username, String password);
}

Normalement, c'est bien, mais il y a un inconvénient. En mettant la méthode de Spring @Service sur les interfaces, nous créons une dépendance supplémentaire et couplons nos interfaces avec une bibliothèque extérieure.

Ensuite, pour tester l'autodétection de nos nouveaux beans de service, créons une implémentation de notre module AuthenticationService :

public class InMemoryAuthenticationService implements AuthenticationService {

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

Nous devons faire attention à notre nouvelle mise en œuvre, InMemoryAuthenticationService n'a pas le @Service sur celui-ci. Nous avons laissé @Service uniquement sur l'interface, AuthenticationService .

Donc, exécutons notre contexte Spring à l'aide d'une configuration de base de Spring Boot :

@SpringBootApplication
public class AuthApplication {

    @Autowired
    private AuthenticationService authService;

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

Lorsque nous lançons notre application, nous pouvons obtenir l'infâme NoSuchBeanDefinitionException et le contexte Spring ne démarre pas.

Par conséquent, le fait de placer @Service sur les interfaces n'est pas suffisant pour l'auto-détection des composants Spring.

2. @Service sur les classes abstraites

Utilisation de la @Service sur les classes abstraites n'est pas courante.

Nous commencerons par définir une classe abstraite en partant de zéro et en mettant l'élément @Service sur celui-ci :

@Service
public abstract class AbstractAuthenticationService {

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

Ensuite, nous étendons AbstractAuthenticationService pour créer une implémentation concrète sans l'annoter :

public class LdapAuthenticationService extends AbstractAuthenticationService {

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

Par conséquent, nous mettons également à jour notre AuthApplication pour injecter la nouvelle classe de service :

@SpringBootApplication
public class AuthApplication {

    @Autowired
    private AbstractAuthenticationService authService;

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

Après avoir exécuté notre AuthApplication le contexte du printemps ne démarre pas. Il se retrouve avec le même NoSuchBeanDefinitionException Encore une exception.

Ainsi, en utilisant @Service sur les classes abstraites n'a pas d'effet dans Spring.

3. @Service sur les classes concrètes

Contrairement à ce que nous avons vu ci-dessus, il est assez courant d'annoter les classes d'implémentation plutôt que les classes abstraites ou les interfaces.

De cette façon, notre but est surtout de dire à Spring que cette classe va être une @Component et le marquer avec un stéréotype spécial, qui est @Service dans notre cas.

Par conséquent, Spring va autodétecter ces classes à partir du classpath et les définir automatiquement comme des beans gérés.

Alors, mettons @Service sur nos classes de service en béton cette fois-ci. Nous aurons une classe qui implémente notre interface et une seconde qui étend la classe abstraite que nous avons définie précédemment :

@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) {
        //...
    }
}

Nous devons noter ici que notre AbstractAuthenticationService n'implémente pas le AuthenticationService ici. Ainsi, nous pouvons les tester indépendamment.

Enfin, nous ajoutons nos deux classes de service dans le répertoire de l'utilisateur. AuthApplication et faire un essai :

@SpringBootApplication
public class AuthApplication {

    @Autowired
    private AuthenticationService inMemoryAuthService;

    @Autowired
    private AbstractAuthenticationService ldapAuthService;

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

Notre test final nous donne un résultat positif, et le contexte Spring démarre sans exception. Les deux services sont automatiquement enregistrés en tant que beans.

Pour des explications complètes, vous pouvez consulter les sites suivants Où doit-on conserver l'annotation Spring @Service ? par Yavuz Taş.

7voto

Kuldeep Tiwari Points 1

L'avantage de mettre l'annotation sur @Service est que cela donne un indice qu'il s'agit d'un service. Je ne sais pas si une classe d'implémentation héritera par défaut de cette annotation.

L'inconvénient est que vous couplez votre interface avec un framework spécifique, par exemple Spring, en utilisant une annotation spécifique à Spring. Comme les interfaces sont censées être découplées de l'implémentation, je ne suggère pas d'utiliser des annotations spécifiques au framework ou une partie objet de votre interface.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X