Spring Component Scanning

Scannen von Federkomponenten

1. Überblick

In diesem Tutorial behandeln wir das Scannen von Komponenten im Frühjahr. Bei der Arbeit mit Spring können wir unsere Klassen mit Anmerkungen versehen, um sie zu Spring Beans zu machen. Abgesehen davon müssenwe can tell Spring where to search for these annotated classes, da nicht alle von ihnen in diesem bestimmten Lauf zu Bohnen werden müssen.

Natürlich gibt es einige Standardeinstellungen für das Scannen von Komponenten, aber wir können die Pakete auch für die Suche anpassen.

Schauen wir uns zunächst die Standardeinstellungen an.

2. @ComponentScan ohne Argumente

2.1. Verwenden von@ComponentScan in einer Frühlingsanwendung

Mit Springwe use the @ComponentScan annotation along with @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan ohne Argumente weist Spring an, das aktuelle Paket und alle seine Unterpakete zu scannen.

Nehmen wir an, wir haben die folgenden@Configuration imcom.example.componentscan.springapp-Paket:

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

Angenommen, wir haben die KomponentenCat undDog im Paketcom.example.componentscan.springapp.animals:

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

Und schließlich haben wir dieRose-Komponente imcom.example.componentscan.springapp.flowers-Paket:

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

Die Ausgabe dermain()-Methode enthält alle Beans descom.example.componentscan.springapp-Pakets und seiner Unterpakete:

springComponentScanApp
cat
dog
rose
exampleBean

Beachten Sie, dass die Hauptanwendungsklasse auch eine Bean ist, da sie mit@Configuration,, einem@Component, versehen ist.

Beachten Sie außerdem, dass die Hauptanwendungsklasse und die Konfigurationsklasse nicht unbedingt identisch sind. Wenn sie unterschiedlich sind, spielt es keine Rolle, wo die Hauptanwendungsklasse abgelegt werden soll. Only the location of the configuration class matters as component scanning starts from its package by default.

Beachten Sie schließlich, dass in unserem Beispiel@ComponentScan äquivalent ist zu:

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

Dabei ist das Argument vonbasePackagesein Paket oder ein Array von Paketen zum Scannen.

2.2. Verwenden von@ComponentScan in einer Spring Boot-Anwendung

Der Trick bei Spring Boot ist, dass viele Dinge implizit passieren. Wir verwenden die Annotation@SpringBootApplication, aber es ist nur eine Kombination aus drei Annotationen:

@Configuration
@EnableAutoConfiguration
@ComponentScan

Erstellen wir eine ähnliche Struktur im Paketcom.example.componentscan.springbootapp. Diesmal wird die Hauptanwendung sein:

package com.example.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));
        }
    }
}

Alle anderen Pakete und Klassen bleiben gleich. Wir kopieren sie einfach in das Paketcom.example.componentscan.springbootappin der Nähe.

Spring Boot scannt Pakete ähnlich wie in unserem vorherigen Beispiel. Überprüfen wir die Ausgabe:

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

Der Grund, warum wir in unserem zweiten Beispiel nur die Existenz der Bohnen überprüfen (im Gegensatz zum Ausdrucken aller Bohnen), ist, dass die Ausgabe zu groß wäre.

Dies liegt an der impliziten Annotation von@EnableAutoConfiguration, durch die Spring Boot automatisch viele Beans erstellt, abhängig von den Abhängigkeiten in der Datei vonpom.xml.

3. @ComponentScan mit Argumenten

Passen wir nun die Pfade für das Scannen an. Angenommen, wir möchten die BeanRoseausschließen.

3.1. @ComponentScan für bestimmte Pakete

Wir können es auf verschiedene Arten tun. Zuerst können wir das Basispaket ändern:

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

Jetzt lautet die Ausgabe:

springComponentScanApp
cat
dog
exampleBean

Mal sehen, was dahinter steckt:

  • springComponentScanApp wird erstellt, da es sich um eine Konfiguration handelt, die als Argument anAnnotationConfigApplicationContext übergeben wird

  • exampleBean ist eine Bean, die in der Konfiguration konfiguriert ist

  • cat unddog befinden sich im angegebenencom.example.componentscan.springapp.animals-Paket

Alle oben aufgeführten Anpassungen gelten auch für Spring Boot. Wir können@ComponentScan zusammen mit@SpringBootApplication verwenden und das Ergebnis ist dasselbe:

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

3.2. @ComponentScan mit Ausschlüssen

Eine andere Möglichkeit ist die Verwendung eines Filters, der das Muster angibt, das von den Klassen ausgeschlossen werden soll:

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

Wir können auch einen anderen Filtertyp alsthe annotation supports several flexible options for filtering the scanned classes wählen:

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

4. Das Standardpaket

Wir sollten vermeiden, die@Configuration Klassein the default package (d. H. durch die Angabe des Pakets überhaupt nicht). In diesem Fall durchsucht Spring alle Klassen in allen Gläsern in einem Klassenpfad. Dies führt zu Fehlern und die Anwendung wird wahrscheinlich nicht gestartet.

5. Fazit

In diesem Artikel haben wir erfahren, welche Pakete Spring standardmäßig scannt und wie diese Pfade angepasst werden.

Wie üblich ist der vollständige Codeover on GitHub verfügbar.