Entendiendo en Spring Boot las anotaciones @Configuration y @Bean

En Spring Boot, @Bean es una anotación a nivel de método que se utiliza para declarar un bean y registrarlo en el contenedor de Spring.

¿Qué es @Configuration en Spring Boot?

La anotación @Configuration se utiliza en Spring Boot para indicar que una clase contiene una o más definiciones bean.

Un bean es un objeto gestionado por el framework Spring y que puede utilizarse para proporcionar servicios o funcionalidades a otras partes de la aplicación.

Cuando una clase está anotada con @Configuration, se trata como una fuente de definiciones de beans, y cualquier método dentro de la clase que esté anotado con @Bean se utilizará para crear y configurar beans.

spring_configuration_beans

@Configuration
public class AppConfig {
    
        // beans definition here

}

¿Qué es un Bean en Spring Boot?

Un Bean es un objeto gestionado por el framework Spring.

Es creado, gestionado y gestionado por el contenedor de Spring. Los beans se pueden utilizar para encapsular y proporcionar servicios, utilidades y funcionalidades a otros componentes de una aplicación.

@Bean es una anotación que se utiliza para declarar un método como bean, por lo que para crear un bean en Spring Boot basta con anotar un método con @Bean.

El método debe devolver un objeto que quieras registrar como bean en el contenedor de Spring.

El contenedor Spring gestionará entonces el ciclo de vida del bean y lo inyectará en otros componentes cuando sea necesario.

He aquí un ejemplo de cómo definir un bean en Spring Boot utilizando la anotación @Bean.

Nótese que esta clase está anotada con @Configuration por lo que podemos crear @Beans allí.

@Configuration
public class AppConfig {

    @Bean
    public MultiplierService multiplier() {
        return new MultiplierService(2);
    }

}

En este ejemplo, MultiplierService es una clase que proporciona un servicio que pueden utilizar otros componentes. El método Multiplier() está anotado con @Bean, lo que indica a Spring que lo trate como un bean. Cuando el contenedor Spring se inicia, llamará a este método para crear una nueva instancia de MultiplierService. Esta instancia será gestionada por Spring y podrá ser inyectada en otros componentes que dependan de ella.

Observa que la anotación @Bean se utiliza dentro de una clase @Configuration, que es un tipo especial de componente Spring que define información de configuración para la aplicación.

Esta es la clase MultiplierService que queremos añadir como un Bean en nuestra Configuration.

public class MultiplierService {

    private final int multiplier;

    public MultiplierService(int multiplier) {
        this.multiplier = multiplier;
    }

    public int multiply(int value) {
        return value * multiplier;
    }

}

Cómo utilizar un Bean que hemos creado

Puedes utilizar un bean que hayas creado mediante autowire en otra clase o componente.

Aquí tienes un ejemplo de Autowired del bean ‘MultiplierService’ en nuestro ‘AppService’:

@Service
public class AppService {

    private final MultiplierService multiplierService;

    public AppService(@Autowired MultiplierService multiplierService) {
        this.multiplierService = multiplierService;
    }

    public int calculate(int aValue) {
        return multiplierService.multiply(aValue);
    }

}

Nota: Realmente se puede omitir @Autowired porque hasta ahora sólo tenemos un Bean definido para la clase y porque si @Autowired no está presente, Spring buscará un bean que satisfaga el constructor.

Cómo dar un nombre a un Bean

Puedes dar un nombre a un bean proporcionando un nombre a la anotación @Bean. la anotación. Este nombre se utilizará como nombre del bean en el contenedor de Spring.

@Bean(name= "multiplierService")
public MultiplierService multiplier() {
    return new MultiplierService(2);
}

En este ejemplo, la anotación @Bean recibe el valor “multiplierService”.

Esto se utilizará como nombre del bean en el contenedor de Spring en lugar del nombre por defecto, que es el nombre del método que declara el bean (en este caso, “multiplicador”).

Si omites el valor de la cadena en la anotación @Bean, Spring utilizará el nombre por defecto basado en el nombre del método.

¿Cómo llamar a un Bean por su nombre?

En Spring Boot, puedes llamar a un bean con un nombre específico utilizando la anotación @Qualifier.

La anotación @Qualifier se utiliza para especificar el nombre del bean que se quiere utilizar cuando hay varios beans del mismo tipo o simplemente cuando queremos declarar particularmente el bean a utilizar.

Aquí tienes un ejemplo:

Con @Qualifier le decimos a Spring exactamente qué bean necesitamos.

@Service
public class AppService {

    private final MultiplierService multiplierService;

    public AppService(@Autowired @Qualifier("multiplierService") MultiplierService multiplierService) {
        this.multiplierService = multiplierService;
    }

    public int calculate(int aValue) {
        return multiplierService.multiply(aValue);
    }

}

Tenga en cuenta que el nombre indicado en la anotación @Qualifier debe coincidir con el nombre del bean que desea utilizar. Si el nombre no coincide con ningún bean del contenedor, Spring lanzará una excepción en tiempo de ejecución.

Ten en cuenta también que si sólo tienes un bean de un tipo determinado, no necesitas utilizar @Qualifier ya que Spring puede conectarlo automáticamente. Sin embargo, si tienes varios beans del mismo tipo, tienes que especificar cuál usar usando @Qualifier.

¿Qué son los nombres de alias?

En Spring Boot, los alias son nombres alternativos que se pueden dar a un bean además de su nombre principal.

Puedes definir nombres de alias para un bean utilizando la anotación @Bean con una cadena de nombres de alias como se muestra en el siguiente ejemplo:

@Configuration
public class AppConfig {

   @Bean(name = {"multiplierService", 
            "multiplierService-alias1", "multiplierService-alias2"})
    public MultiplierService multiplier() {
        return new MultiplierService(2);
    }

}

Puede utilizar cualquier número de nombres de alias para un bean, y los nombres de alias pueden ser cualquier valor de cadena válido. Cuando se hace referencia a un bean por un nombre de alias, Spring lo resuelve al bean primario con ese nombre.

¿Qué son initMethod y destroyMethod en @Bean?

En Spring Boot, initMethod y destroyMethod son atributos opcionales de la anotación @Bean que permiten especificar métodos que deben ser llamados cuando el bean es inicializado o destruido, respectivamente.

Aquí puedes ver cómo utilizar los métodos init y destroy:

@Configuration
public class AppConfig {

    @Bean(name = {"multiplierService",
            "multiplierService-alias1", "multiplierService-alias2"}, 
             initMethod = "init", destroyMethod = "destroy")
    public MultiplierService multiplier() {
        return new MultiplierService(2);
    }

}

En este ejemplo, el método “multiplier()” está anotado con @Bean, que incluye los atributos initMethod y destroyMethod.

El atributo initMethod especifica que se debe llamar a un método llamado “init()” cuando se inicializa el bean, y el atributo destroyMethod especifica que se debe llamar a un método llamado “destroy()” cuando se destruye el bean.

El método init() puede realizar cualquier lógica de inicialización que el bean requiera. Este método es llamado después de que el bean haya sido creado y sus dependencias hayan sido inyectadas, pero antes de que el bean esté disponible para su uso.

El método destroy() puede realizar cualquier lógica de limpieza que requiera el bean. Este método se ejecuta cuando el contenedor Spring se cierra o el bean es destruido por el contenedor.

Ten en cuenta que los métodos especificados en initMethod y destroyMethod deben tener un tipo de retorno void y no tomar argumentos. Si el método tiene un tipo de retorno o toma argumentos, Spring lanzará una excepción en tiempo de ejecución.

public class MultiplierService {

    private final int multiplier;

    public MultiplierService(int multiplier) {
        this.multiplier = multiplier;
    }

    public int multiply(int value) {
        return value * multiplier;
    }

    public void init() {
        System.out.println("Calling init method :)");
    }

    public void destroy() {
        System.out.println("Calling destroy method :(");
    }
}

Ejecutando este ejemplo:

Si ejecutamos este ejemplo completo con esta clase principal de Spring Boot:

@SpringBootApplication
public class SpringBootBeanApplication {

    private final AppService appService;;

    public SpringBootBeanApplication(AppService appService) {
        this.appService = appService;
    }

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

    @PostConstruct
    public void doExamples() {
        System.out.println("Calling bean method with this result: " +  appService.calculate(123));
    }

}

Podemos ver esta Salida:

INFO 17028 --- [           main] c.g.s.SpringBootBeanApplication          : Starting SpringBootBeanApplication using Java 17.0.2 with PID 17028 (C:\dev\spring-boot-examples\spring-boot-bean\target\classes started by gustavo.peiretti in C:\dev\spring-boot-examples\spring-boot-bean)
INFO 17028 --- [           main] c.g.s.SpringBootBeanApplication          : No active profile set, falling back to 1 default profile: "default"
Calling init method :)
Calling bean method with this result: 246
INFO 17028 --- [           main] c.g.s.SpringBootBeanApplication          : Started SpringBootBeanApplication in 0.607 seconds (process running for 1.122)
Calling destroy method :(

Cuál es el ciclo de vida del @Bean

En este ejemplo, el método @Bean se define en una clase @Configuration.

1- La definición del bean se registra en el contenedor de Spring, y el contenedor instantiza e inicializa el bean 2- Spring inyecta cualquier dependencia que el bean necesite. 3- Se llama al método Init. 3- Una vez que el bean está completamente inicializado, está disponible para su uso en la aplicación. 4- Cuando la aplicación se cierra o el bean es destruido por el contenedor, se llama al método destroy especificado en la anotación @Bean.

Spring Boot life cycle

Anotación ConditionalOnProperty con ‘Beans’ Spring

La anotación @ConditionalOnProperty se utiliza para crear condicionalmente un bean Spring dependiendo de la configuración de una propiedad.

conditional-on-property

Por ejemplo, vamos a crear un bean llamado senderMessagesSms si sender.sms tiene el valor true y en caso negativo, se creará senderMessagesEmail.


    @ConditionalOnProperty(name = "sender.sms", havingValue = "true")
    @Bean(name = "senderMessagesSms")
    public SenderMessages senderMessagesSms() {
        return new SenderMessagesSms();
    }

    @ConditionalOnProperty(name = "sender.sms", havingValue = "false")
    @Bean(name = "senderMessagesEmail")
    public SenderMessages senderMessagesEmail() {
        return new SenderMessagesEmail();
    }

Pero, ¿qué pasa si la propiedad no existe? Para este caso podemos utilizar el parámetro matchIfMissing. Así, si la propiedad no está definida se creará el bean con ese parámetro puesto a true.

matchIfMissing = true
    @ConditionalOnProperty(name = "sender.sms", havingValue = "true", matchIfMissing = true)
    @Bean(name = "senderMessagesSms")
    public SenderMessages senderMessagesSms() {
        return new SenderMessagesSms();
    }

    @ConditionalOnProperty(name = "sender.sms", havingValue = "false")
    @Bean(name = "senderMessagesEmail")
    public SenderMessages senderMessagesEmail() {
        return new SenderMessagesEmail();
    }

Conclusión

Este es un resumen de lo que hemos cubierto:

  • En Spring Boot, un @Bean es una anotación a nivel de método que se utiliza para declarar un bean y registrarlo en el contenedor de Spring.
  • Un método @Bean debe definirse en una clase @Configuration, y normalmente devuelve una instancia de una clase que quieras utilizar como bean en tu aplicación.
  • Opcionalmente, puedes especificar un nombre para el bean utilizando el atributo name de la anotación @Bean.
  • También puedes especificar una matriz de nombres de alias para el bean utilizando el atributo value de la anotación @Bean.
  • Puedes utilizar la inyección de dependencias para inyectar un @Bean en otra clase o componente, lo que te permitirá utilizar el bean en tu aplicación.
  • Puedes utilizar los atributos initMethod y destroyMethod de la anotación @Bean para especificar los métodos que serán llamados cuando el bean sea instanciado y destruido.
  • El ciclo de vida de un @Bean en Spring Boot incluye el registro, la instanciación e inicialización, la inyección de dependencias y la destrucción final.
  • Si necesitas crear un bean bajo alguna condición utiliza la anotación ConditionalOnProperty.

En conclusión, @Bean es una potente anotación de Spring Boot que permite declarar beans de forma sencilla e intuitiva. Puedes registrar y utilizar instancias de tus clases como beans en tu aplicación creando métodos @Bean en tus clases @Configuration, y puedes utilizar la arquitectura de inyección de dependencias de Spring para gestionar eficientemente las dependencias de tus componentes.

Este código está en GitHub Spring Boot Code examples

Hi! If you find my posts helpful, please support me by inviting me for a coffee :)

Ver también