Пролетно сканиране на компоненти

1. Общ преглед

В този урок ще разгледаме сканирането на компоненти през пролетта. Когато работим с Spring, можем да анотираме нашите класове, за да ги превърнем в Spring. Но освен това можем да кажем на Spring къде да търсим тези коментирани класове, тъй като не всички от тях трябва да станат боб в този конкретен цикъл.

Разбира се, има някои настройки по подразбиране за сканиране на компоненти, но също така можем да персонализираме пакетите за търсене.

Първо, нека да разгледаме настройките по подразбиране.

2. @ComponentScan без аргументи

2.1. Използване на @ComponentScan в пролетно приложение

С Spring използваме анотацията @ComponentScan заедно с анотацията @Configuration, за да посочим пакетите, които искаме да бъдат сканирани . @ComponentScan без аргументи казва на Spring да сканира текущия пакет и всички негови подпакети .

Да приемем, че имаме следния @Configuration в пакета 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); } } }

Също така, да кажем, че имаме компонентите Cat и Dog в пакета 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 {}

И накрая, имаме компонента Rose в пакета com.baeldung.componentscan.springapp.flowers :

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

Резултатът от метода main () ще съдържа всички компоненти на пакета com.baeldung.componentscan.springapp и неговите подпакети :

springComponentScanApp cat dog rose exampleBean

Обърнете внимание, че основният клас на приложение също е bean, тъй като е коментиран с @Configuration, който е @Component .

Също така имайте предвид, че основният клас на приложение и класът на конфигурацията не са непременно еднакви. Ако те са различни, няма значение къде да поставите основния клас на приложение. Важно е само местоположението на класа на конфигурацията, тъй като сканирането на компоненти започва по подразбиране от неговия пакет .

И накрая, обърнете внимание, че в нашия пример @ComponentScan е еквивалентно на:

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

където аргумент basePackages е пакет или масив от пакети за сканиране.

2.2. Използване на @ComponentScan в Spring Boot Application

Номерът при Spring Boot е, че много неща се случват имплицитно. Използваме анотацията @SpringBootApplication , но това е просто комбинация от три анотации:

@Configuration @EnableAutoConfiguration @ComponentScan

Нека създадем подобна структура в пакета com.baeldung.componentscan.springbootapp . Този път основното приложение ще бъде:

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

Всички други пакети и класове остават същите, ние просто ще ги копираме в близкия пакет com.baeldung.componentscan.springbootapp .

Spring Boot сканира пакети подобно на нашия предишен пример. Нека проверим резултата:

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

Причината, поради която просто проверяваме зърната за съществуването във втория ни пример (за разлика от разпечатването на всички зърна), е, че изходът би бил твърде голям.

Това се дължи на неявната анотация @EnableAutoConfiguration, която кара Spring Boot да създава много зърна автоматично, разчитайки на зависимостите във файла pom.xml .

3. @ComponentScan с аргументи

Сега нека персонализираме пътищата за сканиране. Да приемем например, че искаме да изключим боб Роза .

3.1. @ComponentScan за конкретни пакети

Можем да го направим по няколко начина. Първо, можем да променим базовия пакет:

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

Сега изходът ще бъде:

springComponentScanApp cat dog exampleBean

Нека да видим какво стои зад това:

  • springComponentScanApp се създава, тъй като е конфигурация, предадена като аргумент на AnnotationConfigApplicationContext
  • exampleBean е боб, конфигуриран в конфигурацията
  • котка и куче са в посочения пакет com.baeldung.componentscan.springapp.animals

Всички горепосочени персонализации са приложими и в Spring Boot. Можем да използваме @ComponentScan заедно с @SpringBootApplication и резултатът ще бъде същият:

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

3.2. @ComponentScan с изключения

Друг начин е да се използва филтър, указващ модела за класовете, които да се изключат:

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

Също така можем да изберем различен тип филтър, тъй като анотацията поддържа няколко гъвкави опции за филтриране на сканираните класове :

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

4. Пакетът по подразбиране

Трябва да избягваме поставянето на класа @Configuration в пакета по подразбиране (т.е. като изобщо не посочваме пакета). В този случай Spring просканира всички класове във всички буркани в пътеката на класа. Това причинява грешки и приложението вероятно не се стартира.

5. Заключение

В тази статия научихме кои пакети Spring сканира по подразбиране и как да персонализираме тези пътища.

Както обикновено, пълният код е достъпен в GitHub.