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.
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.
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.
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.
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.
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.
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.