Primavera: @Component versus @Bean

459

Entiendo que la @Componentanotación se introdujo en la primavera 2.5 para deshacerse de la definición del bean xml mediante el escaneo de classpath.

@Beanse introdujo en la primavera 3.0 y se puede usar @Configurationpara deshacerse por completo del archivo xml y usar la configuración de java en su lugar.

¿Habría sido posible reutilizar la @Componentanotación en lugar de introducir la @Beananotación? Tengo entendido que el objetivo final es crear frijoles en ambos casos.

usuario1396576
fuente
44
¿Hay algún lugar donde @Bean se pueda usar aparte de la clase Configuration?
Willa
@Willa Sí, lo hay. Eso se llama Lite mode. Y no es recomendable. Ver aquí: docs.spring.io/spring/docs/current/spring-framework-reference/…
smwikipedia
99
Lo resumiría diciendo que un método con @beandevuelve una instancia personalizable de Spring Bean, mientras @componentdefine una clase que puede ser instanciada posteriormente por Spring IoC Engine cuando sea necesario.
Sebas

Respuestas:

433

@Componenty @Beanhacer dos cosas muy diferentes, y no debe confundirse.

@Component(y @Service, y @Repository) se utilizan para detectar automáticamente y frijoles de auto-configurar mediante el escaneo ruta de clase. Hay una asignación implícita uno a uno entre la clase anotada y el bean (es decir, un bean por clase). El control del cableado es bastante limitado con este enfoque, ya que es puramente declarativo.

@Beanse usa para declarar explícitamente un solo bean, en lugar de dejar que Spring lo haga automáticamente como se indicó anteriormente. Desacopla la declaración del bean de la definición de clase y le permite crear y configurar beans exactamente como lo elija.

Para responder tu pregunta...

¿habría sido posible reutilizar la @Componentanotación en lugar de introducir la @Beananotación?

Claro, probablemente; pero decidieron no hacerlo, ya que los dos son bastante diferentes. La primavera ya es bastante confusa sin enturbiar aún más las aguas.

skaffman
fuente
3
Entonces, ¿solo puedo usar @Componentcuando se necesita cableado automático? Parece @Beanque no puede afectar@Autowired
Jaskey
3
use '@component' para clases basadas en servicios, '@Bean' como objetos más personalizados de fábrica, por ejemplo
fuente de
2
@Jaskey puede utilizar @Autowiredcon @Beansi ha anotado su clase bean con@Configuration
starcorn
66
Lo siento, pero no puedo entender una palabra de tu explicación. Entiendes esto claramente, así que, ¿escribirías una explicación clara o señalarías la documentación adecuada?
Alex Worden
13
Ahora que entiendo el concepto (al leer las respuestas de otras personas), su explicación tiene sentido. Lo que me dice aún más que su explicación no es buena para alguien que aún no comprende los conceptos.
Alex Worden
397

@Componente Preferible para escaneo de componentes y cableado automático.

¿Cuándo deberías usar @Bean ?

A veces, la configuración automática no es una opción. ¿Cuando? Imaginemos que desea conectar componentes de bibliotecas de terceros (no tiene el código fuente, por lo que no puede anotar sus clases con @Component), por lo que no es posible la configuración automática.

La anotación @Bean devuelve un objeto que spring debería registrar como bean en el contexto de la aplicación. El cuerpo del método lleva la lógica responsable de crear la instancia.

MagGGG
fuente
55
Creo que esto tiene más sentido. Si entiendo correctamente, @Componentva a clases en sí mismo mientras @Beanva a métodos de clase (que producen instancias de objetos de clase)
jocull
182

Consideremos que quiero una implementación específica dependiendo de algún estado dinámico. @BeanEs perfecto para ese caso.

@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();
    }
}

Sin embargo, no hay forma de hacerlo @Component.

outdev
fuente
3
¿Cómo llamas a esa clase de ejemplo?
PowerFlower
1
@PowerFlower Este método debe estar en una clase de configuración, anotado con@Configuration
Juh_
98
  1. @Component detecta y configura automáticamente los beans mediante el escaneo de classpath, mientras que @Bean declara explícitamente un solo bean, en lugar de dejar que Spring lo haga automáticamente.
  2. @Component no desacopla la declaración del bean de la definición de clase, mientras que @Bean desacopla la declaración del bean de la definición de clase.
  3. @Component es una anotación de nivel de clase, mientras que @Bean es una anotación de nivel de método y el nombre del método sirve como el nombre del bean.
  4. @Component no necesita ser usado con la anotación @Configuration, donde como anotación @Bean debe usarse dentro de la clase que está anotada con @Configuration .
  5. No podemos crear un bean de una clase usando @Component, si la clase está fuera del contenedor spring, mientras que podemos crear un bean de una clase usando @Bean incluso si la clase está presente fuera del contenedor spring .
  6. @Component tiene diferentes especializaciones como @Controller, @Repository y @Service, mientras que @Bean no tiene especializaciones .
Saurabh Prakash
fuente
3
4. En realidad, @Bean podría declararse en una clase sin configuración. Es conocido como modo lite
voipp
1
Con respecto al punto 5. Creo que colocamos un frijol dentro del contenedor de primavera. Entonces, cada clase está fuera del contenedor de primavera. Supongo que el punto 5 debería ser recompensado
eugen
97

Ambos enfoques tienen como objetivo registrar el tipo de destino en el contenedor Spring.

La diferencia es que @Beanes aplicable a los métodos , mientras que @Componentes aplicable a los tipos .

Por lo tanto, cuando usa @Beananotaciones, controla la lógica de creación de instancias en el cuerpo del método (vea el ejemplo anterior ). Con @Componentanotaciones no puedes.

Nurlan Akashayev
fuente
¿Qué es un tipo?
Jac Frall
20

Veo muchas respuestas y casi en todas partes se menciona que @Component es para el cableado automático donde se escanea el componente y @Bean declara exactamente que el bean se usará de manera diferente. Déjame mostrarte cómo es diferente.

  • @Frijol

Primero es una anotación de nivel de método. Segundo, generalmente se usa para configurar beans en un código java (si no está usando la configuración xml) y luego se llama desde una clase usando el método getBean de ApplicationContext. me gusta

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

class User{
}



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

Es una forma general de anotar un bean y no un bean especializado. Una anotación de nivel de clase y se utiliza para evitar todas esas cosas de configuración a través de la configuración de Java o XML.

Tenemos algo como esto.

@Component
class User {
}

//to get Bean
@Autowired
User user;

Eso es . Se acaba de presentar para evitar todos los pasos de configuración para crear instancias y usar ese bean.

xpioneer
fuente
55
Creo que no es necesario obtener el objeto Usuario de ApplicationContext cuando utiliza el @Beanenfoque. Todavía puede usar @Autowirepara obtener el bean como lo haría en caso de @Component. @Beansimplemente agrega el Bean al Spring Container tal como lo haría @Component. La diferencia es la siguiente. 1. Utilizando @Bean, puede agregar clases de terceros a Spring Container. 2. Usando @Bean, puede obtener la implementación deseada de una interfaz en tiempo de ejecución (Usando el patrón de diseño de fábrica)
Andy
20

Puede utilizar @Beanpara hacer que una clase de terceros existente esté disponible para su contexto de aplicación Spring Framework.

@Bean
public ViewResolver viewResolver() {

    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

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

    return viewResolver;
}

Al usar la @Beananotación, puede ajustar una clase de terceros (puede que no tenga @Componenty puede que no use Spring), como un bean Spring. Y luego, una vez que se ajusta usando @Bean, es como un objeto único y está disponible en el contexto de la aplicación Spring Framework. Ahora puede compartir / reutilizar fácilmente este bean en su aplicación utilizando inyección de dependencia y @Autowired.

Así que piense en la @Beananotación es un contenedor / adaptador para clases de terceros. Desea que las clases de terceros estén disponibles para el contexto de la aplicación Spring Framework.

Al usar @Beanel código anterior, declaro explícitamente un solo bean porque dentro del método, estoy creando explícitamente el objeto usando la newpalabra clave. También estoy llamando manualmente a los métodos setter de la clase dada. Entonces puedo cambiar el valor del campo de prefijo. Por lo tanto, este trabajo manual se denomina creación explícita. Si uso el @Componentpara la misma clase, el bean registrado en el contenedor Spring tendrá un valor predeterminado para el campo de prefijo.

Por otro lado, cuando anotamos una clase con @Component, no es necesario que usemos la newpalabra clave manualmente . Se maneja automáticamente por Spring.

elvis
fuente
1
Sería bueno si esta respuesta se actualizara con un ejemplo de cómo se usa ese bean también
softarn
¿Cómo envolvería un @Bean sobre una clase de terceros si el código fuente no permite modificaciones?
Veritas
16

Cuando usa la @Componentetiqueta, es lo mismo que tener un POJO (Objeto Java antiguo simple) con un método de declaración de vainilla (anotado con @Bean). Por ejemplo, los siguientes métodos 1 y 2 darán el mismo resultado.

Método 1

@Component
public class SomeClass {

    private int number;

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

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

con un bean para 'theNumber':

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

Método 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;
    }
}

con los frijoles para ambos:

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

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

El método 2 le permite mantener juntas las declaraciones de frijol, es un poco más flexible, etc. Incluso puede agregar otro frijol SomeClass que no sea vainilla como el siguiente:

@Bean
SomeClass strawberryClass(){
    return new SomeClass(new Integer(1));
}
Algún chico
fuente
10

Tienes dos formas de generar frijoles. Una es crear una clase con una anotación @Component. El otro es crear un método y anotarlo con @Bean. Para aquellas clases que contienen método con, se @Beandeben anotar con @Configuration Una vez que ejecute su proyecto de primavera, la clase con una @ComponentScananotación escaneará cada clase con @Componentella y restaurará la instancia de esta clase en el Contenedor Ioc. Otra cosa @ComponentScanque haría sería ejecutar los métodos con @Beanél y restaurar el objeto de retorno al Contenedor Ioc como un bean. Entonces, cuando necesite decidir qué tipo de beans desea crear dependiendo de los estados actuales, debe usar@Bean. Puede escribir la lógica y devolver el objeto que desee. Otra cosa que vale la pena mencionar es que el nombre del método @Beanes el nombre predeterminado de bean.

Dai Niu
fuente
6
  • @component y sus especializaciones (@Controller, @service, @repository) permiten la detección automática mediante el escaneo de classpath. Si vemos una clase de componente como @Controller, @service, @repository será escaneado automáticamente por Spring Framework utilizando el escaneo de componentes.
  • @Bean, por otro lado, solo se puede usar para declarar explícitamente un solo bean en una clase de configuración.
  • @Bean solía declarar explícitamente un solo bean, en lugar de dejar que Spring lo hiciera automáticamente. Hace una declaración septada de bean desde la definición de clase.
  • En resumen, @Controller, @service, @repository son para autodetección y @Bean para crear un bean separado de la clase
    - @Controlador
    LoginController de clase pública 
    {--code--}

    - @Configuration
    AppConfig de clase pública {
    @Frijol
    public SessionFactory sessionFactory () 
    {--code--}
alok
fuente
3

@Bean fue creado para evitar el acoplamiento de Spring y sus reglas de negocio en tiempo de compilación. Significa que puede reutilizar las reglas de su negocio en otros marcos como PlayFramework o JEE.

Además, tiene un control total sobre cómo crear beans, donde no es suficiente la instancia predeterminada de Spring.

Escribí una publicación hablando de eso.

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

Daniel Andres Peláez López
fuente
3

Diferencia entre frijol y componente:

Diferencia entre frijol y componente

AzarEJ
fuente
1

1. Acerca de @Component
@Component funciona de manera similar a @Configuration.

Ambos indican que la clase anotada tiene uno o más beans que deben registrarse Spring-IOC-Container.

La clase anotada por @Component, la llamamos Component of Spring. Es un concepto que contiene varios frijoles.

Component classnecesita ser escaneado automáticamente por Spring para registrar esos beans del component class.

2. Acerca de @Bean
@Bean se utiliza para anotar el método de component-class(como se mencionó anteriormente). Indica que la instancia retirada por el método anotado debe registrarse Spring-IOC-Container.

3. Conclusión
La diferencia entre ellos dos es relativamente obvia, se utilizan en different circumstances. El uso general es:

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

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

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

Puntos adicionales de las respuestas anteriores

Digamos que tenemos un módulo que se comparte en múltiples aplicaciones y contiene algunos servicios. No todos son necesarios para cada aplicación.

Si usa @Component en esas clases de servicio y el escaneo de componentes en la aplicación,

podríamos terminar detectando más frijoles de los necesarios

En este caso, tenía que ajustar el filtrado del escaneo de componentes o proporcionar la configuración que incluso los beans no utilizados pueden ejecutar. De lo contrario, el contexto de la aplicación no se iniciará.

En este caso, es mejor trabajar con la anotación @Bean y solo instanciar esos beans,

que se requieren individualmente en cada aplicación

Entonces, esencialmente, use @Bean para agregar clases de terceros al contexto. Y @Component si está solo dentro de su aplicación individual.

AzarEJ
fuente