Konfiguration in Dateien ist nur die halbe Miete. Der Code muss die Werte auch lesen können. Spring bietet dafür mehrere Wege – von einfach bis typsicher.
Die @Value-Annotation injiziert einzelne Werte direkt in
Felder:
# application.yaml
arcade:
max-scores-per-player: 100
default-game: pacman
admin-email: admin@arcade.local@Service
public class LeaderboardService {
@Value("${arcade.max-scores-per-player}")
private int maxScoresPerPlayer;
@Value("${arcade.default-game}")
private String defaultGame;
@Value("${arcade.admin-email}")
private String adminEmail;
public List<Score> getTopScores(String gameId) {
String game = (gameId != null) ? gameId : defaultGame;
return scoreRepository.findTopByGame(game, maxScoresPerPlayer);
}
}Die Syntax ${property.name} verweist auf die Property.
Spring löst den Wert beim Start auf.
Was passiert, wenn eine Property fehlt? Ohne Absicherung: Fehler beim Start. Mit Defaultwert: kein Problem.
// Defaultwert nach dem Doppelpunkt
@Value("${arcade.max-scores-per-player:50}")
private int maxScoresPerPlayer;
@Value("${arcade.feature.new-ui:false}")
private boolean newUiEnabled;
@Value("${arcade.welcome-message:Willkommen!}")
private String welcomeMessage;Wenn arcade.max-scores-per-player nicht definiert ist,
wird 50 verwendet. Praktisch für optionale
Konfiguration.
@Value funktioniert auch mit Constructor Injection:
@Service
public class LeaderboardService {
private final int maxScoresPerPlayer;
private final String defaultGame;
public LeaderboardService(
@Value("${arcade.max-scores-per-player:50}") int maxScoresPerPlayer,
@Value("${arcade.default-game:pacman}") String defaultGame) {
this.maxScoresPerPlayer = maxScoresPerPlayer;
this.defaultGame = defaultGame;
}
}Die Felder können jetzt final sein. Besser für
Immutability.
Bei vielen zusammengehörigen Properties ist @Value
umständlich. @ConfigurationProperties bündelt sie in einer
Klasse:
# application.yaml
arcade:
max-scores-per-player: 100
default-game: pacman
leaderboard:
page-size: 20
cache-duration: 300@ConfigurationProperties(prefix = "arcade")
public class ArcadeProperties {
private int maxScoresPerPlayer = 50;
private String defaultGame = "pacman";
private Leaderboard leaderboard = new Leaderboard();
// Getter und Setter
public int getMaxScoresPerPlayer() { return maxScoresPerPlayer; }
public void setMaxScoresPerPlayer(int max) { this.maxScoresPerPlayer = max; }
public String getDefaultGame() { return defaultGame; }
public void setDefaultGame(String game) { this.defaultGame = game; }
public Leaderboard getLeaderboard() { return leaderboard; }
public void setLeaderboard(Leaderboard lb) { this.leaderboard = lb; }
public static class Leaderboard {
private int pageSize = 20;
private int cacheDuration = 300;
// Getter und Setter
public int getPageSize() { return pageSize; }
public void setPageSize(int size) { this.pageSize = size; }
public int getCacheDuration() { return cacheDuration; }
public void setCacheDuration(int duration) { this.cacheDuration = duration; }
}
}Die Klasse muss aktiviert werden:
@SpringBootApplication
@ConfigurationPropertiesScan // Aktiviert @ConfigurationProperties
public class ArcadeHighscoreApplication {
}Oder alternativ:
@Configuration
@EnableConfigurationProperties(ArcadeProperties.class)
public class AppConfig {
}Die Properties-Klasse wird wie jede andere Bean injiziert:
@Service
public class LeaderboardService {
private final ArcadeProperties properties;
public LeaderboardService(ArcadeProperties properties) {
this.properties = properties;
}
public List<Score> getTopScores(String gameId, int page) {
String game = (gameId != null) ? gameId : properties.getDefaultGame();
int pageSize = properties.getLeaderboard().getPageSize();
return scoreRepository.findTopByGame(game, page, pageSize);
}
}Vorteile gegenüber @Value:
| Situation | Empfehlung |
|---|---|
| Ein einzelner Wert | @Value |
| Wenige unabhängige Werte | @Value |
| Zusammengehörige Werte | @ConfigurationProperties |
| Verschachtelte Struktur | @ConfigurationProperties |
| Validierung nötig | @ConfigurationProperties |
Für das Arcade-Projekt reicht vorerst @Value. Ein
Beispiel im HomeController:
# application.yaml
arcade:
title: "Arcade Highscore API"
version: "1.0"@Controller
public class HomeController {
private final GameService gameService;
@Value("${arcade.title:Arcade}")
private String title;
@Value("${arcade.version:0.0.0}")
private String version;
public HomeController(GameService gameService) {
this.gameService = gameService;
}
@GetMapping("/")
public String home(Model model) {
model.addAttribute("games", gameService.getAllGames());
model.addAttribute("title", title);
model.addAttribute("version", version);
return "index";
}
}Die Werte erscheinen jetzt auf der Landingpage – konfigurierbar, ohne Code-Änderung.