16 Component Scan

Spring muss wissen, welche Klassen es verwalten soll. Du könntest jede Bean manuell registrieren – aber das wäre mühsam. Stattdessen scannt Spring automatisch nach Komponenten. Dieser Mechanismus heißt Component Scan.

16.1 Das Prinzip

Beim Start durchsucht Spring bestimmte Packages nach Klassen mit speziellen Annotationen. Jede gefundene Klasse wird als Bean registriert.

Spring findet nicht alle Klassen – nur die, die als Komponenten markiert sind. Domain-Klassen wie Player, Game, Score werden ignoriert. Sie haben keine Spring-Annotationen.

16.2 Wo der Scan startet

Der Component Scan beginnt beim Package der Hauptklasse. Im Arcade-Projekt:

package de.digitalfrontiers.arcade;

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

Die Annotation @SpringBootApplication enthält @ComponentScan. Ohne explizite Konfiguration scannt Spring ab de.digitalfrontiers.arcade – dem Package dieser Klasse.

Alles unterhalb von de.digitalfrontiers.arcade wird gefunden. Alles außerhalb nicht.

16.3 Die häufigste Fehlerquelle

Ein Klassiker bei Spring-Einsteigern: Die Bean wird nicht gefunden.

***************************
APPLICATION FAILED TO START
***************************

Parameter 0 of constructor in de.digitalfrontiers.arcade.service.GameService 
required a bean of type 'de.digitalfrontiers.arcade.repository.GameRepository' 
that could not be found.

Ursache Nummer eins: Die Klasse liegt im falschen Package.

de.digitalfrontiers.arcade/
├── ArcadeHighscoreApplication.java  ← Scan startet hier
├── service/
│   └── GameService.java             ← wird gefunden
└── repository/
    └── InMemoryGameRepository.java  ← wird gefunden

de.digitalfrontiers.common/          ← AUSSERHALB des Scans!
└── SharedRepository.java            ← wird NICHT gefunden

Wenn eine Komponente nicht gefunden wird, prüfe zuerst das Package.

16.4 Scan-Bereich erweitern

Manchmal liegen Komponenten außerhalb des Standard-Packages. Du kannst den Scan explizit konfigurieren:

@SpringBootApplication
@ComponentScan(basePackages = {
    "de.digitalfrontiers.arcade",
    "de.digitalfrontiers.common"
})
public class ArcadeHighscoreApplication {
    // ...
}

Jetzt werden beide Package-Bäume gescannt.

Eine Alternative mit Typ-Sicherheit:

@ComponentScan(basePackageClasses = {
    ArcadeHighscoreApplication.class,
    CommonConfiguration.class
})

Statt Strings gibst du Klassen an. Der Compiler prüft, ob sie existieren.

16.5 Was der Scan ignoriert

Nicht jede Klasse im Package wird zur Bean. Spring sucht nach bestimmten Annotationen:

Annotation Wird gescannt
@Component Ja
@Service Ja
@Repository Ja
@Controller Ja
@RestController Ja
@Configuration Ja
Keine Annotation Nein

Eine Klasse ohne diese Annotationen wird ignoriert – auch wenn sie im richtigen Package liegt.

// Wird gefunden
@Service
public class GameService { }

// Wird NICHT gefunden
public class GameHelper { }

Der GameHelper ist unsichtbar für Spring. Wenn du ihn brauchst, musst du ihn selbst instanziieren oder als Bean registrieren.

16.6 Performance-Aspekt

Component Scan kostet Zeit. Spring muss jede Klasse im Package-Baum laden und auf Annotationen prüfen. Bei kleinen Projekten unmerklich, bei großen Anwendungen mit tausenden Klassen spürbar.

Deshalb: Halte den Scan-Bereich so klein wie möglich. Scanne nicht de oder com – das wäre der gesamte Classpath.

Die Standard-Konfiguration – Scan ab dem Application-Package – ist fast immer richtig.