Escaneo de componentes de resorte

1. Información general

En este tutorial, cubriremos el escaneo de componentes en Spring. Cuando trabajamos con Spring, podemos anotar nuestras clases para convertirlas en Spring beans. Pero, además de eso, podemos decirle a Spring dónde buscar estas clases anotadas ya que no todas deben convertirse en beans en esta ejecución en particular.

Por supuesto, existen algunos valores predeterminados para el análisis de componentes, pero también podemos personalizar los paquetes para la búsqueda.

Primero, veamos la configuración predeterminada.

2. @ComponentScan sin argumentos

2.1. Usando @ComponentScan en una aplicación Spring

Con Spring, usamos la anotación @ComponentScan junto con la anotación @Configuration para especificar los paquetes que queremos escanear . @ComponentScan sin argumentos le dice a Spring que escanee el paquete actual y todos sus subpaquetes .

Digamos que tenemos la siguiente @Configuration en el paquete com.baeldung.componentscan.springapp :

@Configuration @ComponentScan public class SpringComponentScanApp { private static ApplicationContext applicationContext; @Bean public ExampleBean exampleBean() { return new ExampleBean(); } public static void main(String[] args) { applicationContext = new AnnotationConfigApplicationContext(SpringComponentScanApp.class); for (String beanName : applicationContext.getBeanDefinitionNames()) { System.out.println(beanName); } } }

Además, digamos que tenemos los componentes Cat y Dog en el paquete com.baeldung.componentscan.springapp.animals :

package com.baeldung.componentscan.springapp.animals; // ... @Component public class Cat {}
package com.baeldung.componentscan.springapp.animals; // ... @Component public class Dog {}

Y finalmente, tenemos el componente Rose en el paquete com.baeldung.componentscan.springapp.flowers :

package com.baeldung.componentscan.springapp.flowers; // ... @Component public class Rose {}

La salida del método main () contendrá todos los beans del paquete com.baeldung.componentscan.springapp y de sus subpaquetes :

springComponentScanApp cat dog rose exampleBean

Tenga en cuenta que la clase de aplicación principal también es un bean ya que está anotado con @Configuration, que es un @Component .

Además, tenga en cuenta que la clase de aplicación principal y la clase de configuración no son necesariamente las mismas. Si son diferentes, no importa dónde colocar la clase de aplicación principal. Solo importa la ubicación de la clase de configuración, ya que el análisis de componentes comienza desde su paquete de forma predeterminada .

Finalmente, tenga en cuenta que en nuestro ejemplo @ComponentScan es equivalente a:

@ComponentScan(basePackages = "com.baeldung.componentscan.springapp")

donde el argumento basePackages es un paquete o una matriz de paquetes para escanear.

2.2. Usando @ComponentScan en una aplicación Spring Boot

El truco con Spring Boot es que muchas cosas suceden implícitamente. Usamos la anotación @SpringBootApplication , pero es solo una combinación de tres anotaciones:

@Configuration @EnableAutoConfiguration @ComponentScan

Creemos una estructura similar en el paquete com.baeldung.componentscan.springbootapp . Esta vez la aplicación principal será:

package com.baeldung.componentscan.springbootapp; // ... @SpringBootApplication public class SpringBootComponentScanApp { private static ApplicationContext applicationContext; @Bean public ExampleBean exampleBean() { return new ExampleBean(); } public static void main(String[] args) { applicationContext = SpringApplication.run(SpringBootComponentScanApp.class, args); checkBeansPresence( "cat", "dog", "rose", "exampleBean", "springBootComponentScanApp"); } private static void checkBeansPresence(String... beans) { for (String beanName : beans) { System.out.println("Is " + beanName + " in ApplicationContext: " + applicationContext.containsBean(beanName)); } } }

Todos los demás paquetes y clases siguen siendo los mismos, simplemente los copiaremos en el paquete com.baeldung.componentscan.springbootapp cercano .

Spring Boot escanea paquetes de manera similar a nuestro ejemplo anterior. Comprobemos la salida:

Is cat in ApplicationContext: true Is dog in ApplicationContext: true Is rose in ApplicationContext: true Is exampleBean in ApplicationContext: true Is springBootComponentScanApp in ApplicationContext: true

La razón por la que solo estamos comprobando la existencia de los beans en nuestro segundo ejemplo (en lugar de imprimir todos los beans) es que la salida sería demasiado grande.

Esto se debe a la anotación @EnableAutoConfiguration implícita que hace que Spring Boot cree muchos beans automáticamente, basándose en las dependencias en el archivo pom.xml .

3. @ComponentScan con argumentos

Ahora personalicemos las rutas para escanear. Por ejemplo, digamos que queremos excluir el frijol rosa .

3.1. @ComponentScan para paquetes específicos

Podemos hacerlo de varias formas. Primero, podemos cambiar el paquete base:

@ComponentScan(basePackages = "com.baeldung.componentscan.springapp.animals") @Configuration public class SpringComponentScanApp {   // ... }

Ahora la salida será:

springComponentScanApp cat dog exampleBean

Veamos qué hay detrás de esto:

  • springComponentScanApp se crea como una configuración que se pasa como argumento al AnnotationConfigApplicationContext
  • exampleBean es un bean configurado dentro de la configuración
  • gato y perro están en el paquete com.baeldung.componentscan.springapp.animals especificado

Todas las personalizaciones mencionadas anteriormente también son aplicables en Spring Boot. Podemos usar @ComponentScan junto con @SpringBootApplication y el resultado será el mismo:

@SpringBootApplication @ComponentScan(basePackages = "com.baeldung.componentscan.springbootapp.animals")

3.2. @ComponentScan con exclusiones

Otra forma es usar un filtro, especificando el patrón para que las clases excluyan:

@ComponentScan(excludeFilters = @ComponentScan.Filter(type=FilterType.REGEX, pattern="com\\.baeldung\\.componentscan\\.springapp\\.flowers\\..*"))

También podemos elegir un tipo de filtro diferente, ya que la anotación admite varias opciones flexibles para filtrar las clases escaneadas :

@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Rose.class))

4. El paquete predeterminado

Debemos evitar poner la clase @Configuration en el paquete predeterminado (es decir, no especificar el paquete en absoluto). En este caso, Spring escanea todas las clases en todos los archivos jar en un classpath. Eso provoca errores y la aplicación probablemente no se inicia.

5. Conclusión

En este artículo, hemos aprendido qué paquetes escanea Spring de forma predeterminada y cómo personalizar estas rutas.

Como de costumbre, el código completo está disponible en GitHub.