Printemps: @Component contre @Bean


459

Je comprends que l' @Componentannotation a été introduite au printemps 2.5 afin de se débarrasser de la définition du bean xml en utilisant l'analyse de chemin de classe.

@Beana été introduit au printemps 3.0 et peut être utilisé avec @Configurationpour se débarrasser complètement du fichier xml et utiliser la configuration java à la place.

Aurait-il été possible de réutiliser l' @Componentannotation au lieu d'introduire une @Beanannotation? Je crois comprendre que l'objectif final est de créer des beans dans les deux cas.


4
Existe-t-il un endroit où @Bean peut être utilisé en dehors de la classe Configuration?
Willa


@Willa Oui, il y en a. Ça s'appelle Lite mode. Et ce n'est pas recommandé. Voir ici: docs.spring.io/spring/docs/current/spring-framework-reference/…
smwikipedia

9
Je le résumerais en disant qu'une méthode avec @beanrenvoie une instance personnalisable de Spring Bean, tout en @componentdéfinissant une classe qui peut être instanciée plus tard par le moteur Spring IoC en cas de besoin.
Sebas

Réponses:


433

@Componentet @Beanfaire deux choses très différentes, et ne doit pas être confondu.

@Component(et @Serviceet @Repository) sont utilisés pour détecter et configurer automatiquement les beans à l'aide de l'analyse de chemin de classe. Il existe un mappage un à un implicite entre la classe annotée et le bean (c'est-à-dire un bean par classe). Le contrôle du câblage est assez limité avec cette approche, car il est purement déclaratif.

@Beanest utilisé pour déclarer explicitement un seul bean, plutôt que de laisser Spring le faire automatiquement comme ci-dessus. Il dissocie la déclaration du bean de la définition de classe et vous permet de créer et de configurer des beans exactement comme vous le souhaitez.

Pour répondre à ta question...

aurait-il été possible de réutiliser l' @Componentannotation au lieu d'introduire une @Beanannotation?

Bien sûr, probablement; mais ils ont choisi de ne pas le faire, car les deux sont très différents. Le printemps est déjà assez déroutant sans embrouiller davantage les eaux.


3
Je ne peux donc l'utiliser que @Componentlorsque le câblage automatique est nécessaire? Il semble que @Beancela ne peut pas affecter@Autowired
Jaskey

3
utiliser '@component' pour les classes basées sur les services, '@Bean' comme objets plus personnalisés en usine, par exemple la source de données jdbc
Junchen Liu

2
@Jaskey, vous pouvez utiliser @Autowiredavec @Beansi vous avez annoté votre classe de haricots avec@Configuration
starcorn

6
Désolé mais je ne comprends pas un mot de votre explication. Vous comprenez clairement cela, veuillez donc écrire une explication claire ou indiquer la documentation appropriée?
Alex Worden

13
Maintenant que je comprends le concept (en lisant les réponses des autres), votre explication a du sens. Ce qui m'indique d'autant plus que votre explication n'est pas bonne pour quiconque ne comprend pas déjà les concepts.
Alex Worden

397

@Component Préférable pour la numérisation des composants et le câblage automatique.

Quand devriez-vous utiliser @Bean ?

Parfois, la configuration automatique n'est pas une option. Quand? Imaginons que vous souhaitiez câbler des composants à partir de bibliothèques tierces (vous n'avez pas le code source, vous ne pouvez donc pas annoter ses classes avec @Component), donc la configuration automatique n'est pas possible.

L' annotation @Bean renvoie un objet que spring devrait enregistrer en tant que bean dans le contexte de l'application. Le corps de la méthode porte la logique responsable de la création de l'instance.


5
Je pense que cela a le plus de sens. Si je comprends bien, @Componentva sur les classes elles-mêmes tandis que @Beansur les méthodes de classe (qui produisent des instances d'objets de classe).
jocull

182

Considérons que je souhaite une implémentation spécifique en fonction d'un état dynamique. @Beanest parfait pour ce cas.

@Bean
@Scope("prototype")
public SomeService someService() {
    switch (state) {
    case 1:
        return new Impl1();
    case 2:
        return new Impl2();
    case 3:
        return new Impl3();
    default:
        return new Impl();
    }
}

Cependant, il n'y a aucun moyen de le faire avec @Component.


3
Comment vous appelez cette classe d'exemple?
PowerFlower

1
@PowerFlower Cette méthode doit être dans une classe de configuration, annotée avec@Configuration
Juh_

98
  1. @Component détecte et configure automatiquement les beans à l'aide de l'analyse du chemin de classe tandis que @Bean déclare explicitement un seul bean, plutôt que de laisser Spring le faire automatiquement.
  2. @Component ne découpler pas la déclaration du grain de la définition de la classe où que @Bean découple la déclaration du grain de la définition de la classe.
  3. @Component est une annotation au niveau de la classe tandis que @Bean est une annotation au niveau de la méthode et le nom de la méthode sert de nom au bean.
  4. @Component n'a pas besoin d'être utilisé avec l' annotation @Configuration alors que l'annotation @Bean doit être utilisée dans la classe qui est annotée avec @Configuration .
  5. Nous ne pouvons pas créer un bean d'une classe en utilisant @Component, si la classe est en dehors du conteneur de ressort alors que nous pouvons créer un bean d'une classe en utilisant @Bean même si la classe est présente en dehors du conteneur de printemps .
  6. @Component a différentes spécialisations comme @Controller, @Repository et @Service tandis que @Bean n'a aucune spécialisation .

3
4. En fait, @Bean peut être déclaré dans une classe sans configuration. Il est connu comme le mode lite
voipp

1
En ce qui concerne le point 5. Je pense que nous avons mis un haricot à l'intérieur du récipient à ressort. Ainsi, chaque classe est en dehors du conteneur de printemps. Je suppose que le point 5 devrait être récompensé
eugen

97

Les deux approches visent à enregistrer le type de cible dans le conteneur Spring.

La différence est qu'elle @Beans'applique aux méthodes , alors qu'elle @Components'applique aux types .

Par conséquent, lorsque vous utilisez une @Beanannotation, vous contrôlez la logique de création d'instance dans le corps de la méthode (voir l' exemple ci-dessus ). Avec l' @Componentannotation, vous ne pouvez pas.


Qu'est-ce qu'un type?
Jac Frall

20

Je vois beaucoup de réponses et presque partout son @Component mentionné est pour le câblage automatique où le composant est analysé et @Bean déclare exactement que le bean doit être utilisé différemment. Permettez-moi de montrer en quoi c'est différent.

  • @Haricot

C'est d'abord une annotation au niveau de la méthode. Deuxièmement, vous utilisez généralement pour configurer les beans dans un code java (si vous n'utilisez pas la configuration xml), puis appelez-le à partir d'une classe à l'aide de la méthode getBean d'ApplicationContext. comme

 @Configuration
class MyConfiguration{
    @Bean
    public User getUser(){
        return new User();
    }
}

class User{
}



//Getting Bean 
User user = applicationContext.getBean("getUser");
  • @Composant

C'est une manière générale d'annoter un bean et non un bean spécialisé. Une annotation au niveau de la classe et est utilisée pour éviter toutes ces choses de configuration via la configuration java ou xml.

Nous obtenons quelque chose comme ça.

@Component
class User {
}

//to get Bean
@Autowired
User user;

C'est ça . Il vient d'être introduit pour éviter toutes les étapes de configuration pour instancier et utiliser ce bean.


6
Je pense qu'il n'est pas nécessaire d'obtenir l'objet User d'ApplicationContext lorsque vous utilisez l' @Beanapproche. Vous pouvez toujours utiliser @Autowirepour obtenir le bean comme vous le feriez en cas de @Component. @Beanajoute simplement le Bean au Spring Container comme le ferait @Component. La différence est la suivante. 1. À l'aide de @Bean, vous pouvez ajouter des classes tierces à Spring Container. 2. En utilisant @Bean, vous pouvez obtenir l'implémentation souhaitée d'une interface au moment de l'exécution (en utilisant le modèle de conception d'usine)
Andy

20

Vous pouvez utiliser @Beanpour rendre une classe tierce existante disponible pour votre contexte d'application de framework Spring.

@Bean
public ViewResolver viewResolver() {

    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

    viewResolver.setPrefix("/WEB-INF/view/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

En utilisant l' @Beanannotation, vous pouvez encapsuler une classe tierce (elle peut ne pas avoir @Componentet il ne peut pas utiliser Spring), en tant que bean Spring. Et puis une fois qu'il est encapsulé à l'aide @Bean, il est en tant qu'objet singleton et disponible dans votre contexte d'application de framework Spring. Vous pouvez désormais facilement partager / réutiliser ce bean dans votre application en utilisant l'injection de dépendance et @Autowired.

Pensez donc à l' @Beanannotation est un wrapper / adaptateur pour les classes tierces. Vous souhaitez rendre les classes tierces disponibles pour votre contexte d'application de framework Spring.

En utilisant @Beandans le code ci-dessus, je déclare explicitement un seul bean car à l'intérieur de la méthode, je crée explicitement l'objet à l'aide du newmot - clé. J'appelle également manuellement les méthodes setter de la classe donnée. Je peux donc changer la valeur du champ préfixe. Ce travail manuel est donc appelé création explicite. Si j'utilise le @Componentpour la même classe, le bean enregistré dans le conteneur Spring aura la valeur par défaut pour le champ préfixe.

En revanche, lorsque nous annotons une classe avec @Component, pas besoin d'utiliser manuellement le newmot - clé. Il est géré automatiquement par Spring.


1
Ce serait bien si cette réponse était mise à jour avec un exemple de la façon dont ce bean est également utilisé
softarn

Comment emballeriez-vous un @Bean sur une classe tierce si le code source ne permet pas de modification?
veritas

16

Lorsque vous utilisez la @Componentbalise, c'est la même chose que d'avoir un POJO (Plain Old Java Object) avec une méthode de déclaration de gousse de vanille (annotée avec @Bean). Par exemple, les méthodes 1 et 2 suivantes donneront le même résultat.

Méthode 1

@Component
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

avec un bean pour 'theNumber':

@Bean
Integer theNumber(){
    return new Integer(3456);
}

Méthode 2

//Note: no @Component tag
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

avec les haricots pour les deux:

@Bean
Integer theNumber(){
    return new Integer(3456);
}

@Bean
SomeClass someClass(Integer theNumber){
    return new SomeClass(theNumber);
}

La méthode 2 vous permet de conserver les déclarations de bean ensemble, c'est un peu plus flexible, etc. Vous pouvez même ajouter un autre bean SomeClass non vanille comme le suivant:

@Bean
SomeClass strawberryClass(){
    return new SomeClass(new Integer(1));
}

10

Vous avez deux façons de générer des beans. L'une consiste à créer une classe avec une annotation @Component. L'autre consiste à créer une méthode et à l'annoter avec @Bean. Pour les classes contenant la méthode avec @Beandoivent être annotées avec @Configuration Une fois que vous exécutez votre projet Spring, la classe avec une @ComponentScanannotation analysera chaque classe avec @Componentet restaurera l'instance de cette classe dans le conteneur Ioc. Une autre chose @ComponentScanque faire serait d'exécuter les méthodes avec @Beanet de restaurer l'objet de retour dans le conteneur Ioc en tant que bean. Ainsi, lorsque vous devez décider du type de beans que vous souhaitez créer en fonction des états actuels, vous devez utiliser@Bean. Vous pouvez écrire la logique et renvoyer l'objet que vous souhaitez. Une autre chose à mentionner est le nom de la méthode avec @Beanle nom par défaut du bean.


6
  • @component et ses spécialisations (@Controller, @service, @repository) permettent une détection automatique à l'aide de l'analyse de chemin de classe. Si nous voyons une classe de composants comme @Controller, @service, @repository sera analysé automatiquement par le framework Spring en utilisant l'analyse des composants.
  • @Bean, en revanche, ne peut être utilisé que pour déclarer explicitement un seul bean dans une classe de configuration.
  • @Bean utilisé pour déclarer explicitement un seul bean, plutôt que de laisser Spring le faire automatiquement. Sa déclaration de haricot cloisonnée de la définition de classe.
  • En bref @Controller, @service, @repository sont pour la détection automatique et @Bean pour créer un bean séparé à partir de la classe
    - @Manette
    classe publique LoginController 
    {--code--}

    - @Configuration
    classe publique AppConfig {
    @Haricot
    public SessionFactory sessionFactory () 
    {--code--}

3

@Bean a été créé pour éviter de coupler Spring et vos règles métier lors de la compilation. Cela signifie que vous pouvez réutiliser vos règles métier dans d'autres cadres tels que PlayFramework ou JEE.

De plus, vous avez un contrôle total sur la façon de créer des beans, où il ne suffit pas de l'instanciation Spring par défaut.

J'ai écrit un article pour en parler.

https://coderstower.com/2019/04/23/factory-methods-decoupling-ioc-container-abstraction/



1

1. À propos de @Component
@Component fonctionne de manière similaire à @Configuration.

Ils indiquent tous les deux que la classe annotée a un ou plusieurs beans à enregistrer Spring-IOC-Container.

La classe annotée par @Component, nous l'appelons Component of Spring. C'est un concept qui contient plusieurs beans.

Component classdoit être analysé automatiquement par Spring pour enregistrer ces beans de la component class.

2. À propos de @Bean
@Bean est utilisé pour annoter la méthode de component-class(comme mentionné ci-dessus). Il indique que l'instance retured par la méthode annotée doit être enregistrée dans Spring-IOC-Container.

3. Conclusion
La différence entre les deux est relativement évidente, ils sont utilisés dans different circumstances. L'utilisation générale est:

    // @Configuration is implemented by @Component
    @Configuration
    public ComponentClass {

      @Bean
      public FirstBean FirstBeanMethod() {
        return new FirstBean();
      }

      @Bean
      public SecondBean SecondBeanMethod() {
        return new SecondBean();
      }
    }

0

Points supplémentaires des réponses ci-dessus

Disons que nous avons un module qui est partagé dans plusieurs applications et qui contient quelques services. Tous ne sont pas nécessaires pour chaque application.

Si vous utilisez @Component sur ces classes de service et l'analyse des composants dans l'application,

nous pourrions finir par détecter plus de haricots que nécessaire

Dans ce cas, vous avez dû ajuster le filtrage de l'analyse des composants ou fournir la configuration que même les beans inutilisés peuvent exécuter. Sinon, le contexte d'application ne démarre pas.

Dans ce cas, il est préférable de travailler avec l'annotation @Bean et d'instancier uniquement ces beans,

qui sont requis individuellement dans chaque application

Donc, essentiellement, utilisez @Bean pour ajouter des classes tierces au contexte. Et @Component s'il est juste à l'intérieur de votre application unique.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.