Spring Boot Basic – Tag 5 von 10
Von Elyndra Valen, Senior Entwicklerin bei Java Fleet Systems Consulting

📍 Deine Position im Kurs
| Tag | Thema | Status |
|---|---|---|
| ✅ 1 | Erste REST API | Abgeschlossen |
| ✅ 2 | Spring Container & DI | Abgeschlossen |
| ✅ 3 | @Controller & Thymeleaf Basics | Abgeschlossen |
| ✅ 4 | Thymeleaf Forms & MVC-Pattern | Abgeschlossen |
| → 5 | Konfiguration & Logging | 👉 DU BIST HIER! |
| 6 | DI & AOP im Detail | Noch nicht freigeschaltet |
| 7 | Scopes in Spring | Noch nicht freigeschaltet |
| 8 | WebSockets | Noch nicht freigeschaltet |
| 9 | JAX-RS in Spring Boot | Noch nicht freigeschaltet |
| 10 | Integration & Abschluss | Noch nicht freigeschaltet |
Modul: Spring Boot Basic (10 Arbeitstage)
Dein Ziel: Professionelle Konfiguration & sinnvolles Logging beherrschen!
📋 Voraussetzungen
Du brauchst:
- ✅ Tag 1-4 abgeschlossen
- ✅ PersonViewController & PersonService funktionieren
- ✅ Grundverständnis von Spring Boot
Tag 4 verpasst? → Hier geht’s zum Blogbeitrag Tag 4
⚡ Was du heute lernst:
Gestern: Du hast Formulare und MVC-Pattern gemeistert.
Heute: Du lernst, wie du deine Spring Boot App professionell konfigurierst und Logging richtig einsetzt!
Das Problem:
- Entwicklung braucht andere Einstellungen als Production
- Debugging ohne Logging ist die Hölle
- Hardcoded Werte im Code sind unprofessionell
- Test-Daten müssen beim Start geladen werden
- Secrets gehören NICHT in den Code!
Die Lösung:
- application.properties verstehen und nutzen
- Profile (dev, test, prod)
- Bootstrap-Klasse für Initial-Daten
- @Value und @ConfigurationProperties
- SLF4J & Logback richtig nutzen
🎯 Dein Lernpfad heute:
Du arbeitest heute in mehreren aufbauenden Schwierigkeitsstufen. Arbeite in deinem eigenen Tempo durch die Schritte:
🟢 Grundlagen (Schritte 1-5)
Was du lernst:
- application.properties verstehen
- Profile (dev, prod) erstellen und nutzen
- @Value für einzelne Properties
- @ConfigurationProperties für strukturierte Configs
- SLF4J-Logging Basics
- Log-Level verstehen und anwenden
Ziel: Funktionierende Multi-Environment-Konfiguration + Logging in Service/Controller
🟡 Professional (Schritte 6-7)
Was du lernst:
- Logging konfigurieren (pro Package/Profil)
- Logs in Dateien schreiben
- Log-Pattern anpassen
- Praktisches Logging-Beispiel
Ziel: Production-Ready Logging-Setup
🔵 Bonus: Enterprise Features (Schritte 8-10)
Was du lernst:
- Secrets & Umgebungsvariablen
- Bootstrap-Klasse für Test-Daten
- CommandLineRunner Pattern
- Profile-spezifische Bootstraps
- Logback-XML Konfiguration (Optional)
Ziel: Enterprise-Level Configuration Management
💡 Tipp: Die Grundlagen (Schritte 1-5) sind essenziell – jede Spring Boot App braucht Properties und Logging! Professional (Schritte 6-7) ist sehr empfehlenswert für echte Projekte. Die Bonus-Features zeigen Enterprise-Patterns, die du in größeren Firmen siehst.
💻 Los geht’s!
🟢 GRUNDLAGEN
Schritt 1: application.properties verstehen
1.1 Was ist das überhaupt?
Spring Boot liest beim Start die Konfigurationsdatei:
src/main/resources/application.properties
Hier definierst du ALLES: Server-Port, Datenbank, Logging, eigene Einstellungen, etc.
1.2 Deine erste application.properties
Erstelle/Erweitere: src/main/resources/application.properties
# Spring Boot Konfiguration - Persons App
# Server
server.port=8080
server.servlet.context-path=/
# Application Name
spring.application.name=persons-app
# Thymeleaf
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
# Logging
logging.level.root=INFO
logging.level.com.example.helloworldapi=DEBUG
logging.pattern.console=%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
Teste es:
mvn spring-boot:run
Du solltest sehen:
10:30:45.123 INFO 12345 --- [main] c.e.h.HelloWorldApiApplication : Starting HelloWorldApiApplication...
Schritt 2: Profile – Verschiedene Umgebungen
2.1 Das Problem
Development:
- Server-Port 8080
- Thymeleaf Cache AUS (Änderungen sofort sichtbar)
- Debug-Logging AN
- Detaillierte Fehlerseiten
Production:
- Server-Port 8080 (oder 80/443)
- Thymeleaf Cache AN (Performance!)
- Info-Logging nur
- Keine Fehlerdetails nach außen
Wir brauchen unterschiedliche Konfigurationen!
2.2 Profile anlegen
Erstelle 3 Dateien:
application.properties(Basis – gilt immer)application-dev.properties(Development)application-prod.properties(Production)
application.properties (Basis):
# Spring Boot Basis-Konfiguration
# Application Name
spring.application.name=persons-app
# Standard-Profil
spring.profiles.active=dev
# Basis-Logging Pattern
logging.pattern.console=%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
application-dev.properties:
# Development Konfiguration # Server server.port=8080 # Thymeleaf ohne Cache spring.thymeleaf.cache=false # Verbose Logging logging.level.root=INFO logging.level.com.example.helloworldapi=DEBUG logging.level.org.springframework.web=DEBUG
application-prod.properties:
# Production Konfiguration # Server server.port=8080 server.error.include-message=never server.error.include-stacktrace=never # Thymeleaf mit Cache spring.thymeleaf.cache=true # Weniger Logging logging.level.root=WARN logging.level.com.example.helloworldapi=INFO # Logging in Datei logging.file.name=/var/log/persons-app/application.log logging.file.max-size=10MB logging.file.max-history=30
2.3 Profile aktivieren
Methode 1: In application.properties
spring.profiles.active=dev
Methode 2: Beim Start (BESSER!)
# Development mvn spring-boot:run -Dspring-boot.run.profiles=dev # Production java -jar target/persons-app.jar --spring.profiles.active=prod
Methode 3: Umgebungsvariable
export SPRING_PROFILES_ACTIVE=prod java -jar target/persons-app.jar
2.4 Testen
Dev-Profil:
mvn spring-boot:run -Dspring-boot.run.profiles=dev
Öffne: http://localhost:8080/persons
In den Logs siehst du:
10:30:45.123 DEBUG c.e.h.service.PersonService : Getting all persons...
Prod-Profil:
mvn spring-boot:run -Dspring-boot.run.profiles=prod
Öffne: http://localhost:8080/persons
In den Logs siehst du:
10:30:45.123 INFO c.e.h.service.PersonService : PersonService initialized
DEBUG-Logs sind weg! ✅
Schritt 3: @Value – Einzelne Properties auslesen
3.1 Eigene Properties definieren
In application.properties:
# Eigene App-Konfiguration app.name=Persons Management System app.version=1.0.0 app.max-persons=100 app.features.email-enabled=true app.features.export-enabled=false
3.2 @Value im Controller nutzen
PersonViewController.java:
package com.example.helloworldapi.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
@Controller
@RequiredArgsConstructor
public class PersonViewController {
private final PersonService personService;
// Properties aus application.properties einlesen
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String appVersion;
@Value("${app.max-persons}")
private int maxPersons;
@Value("${app.features.email-enabled}")
private boolean emailEnabled;
@GetMapping("/persons")
public String showPersons(Model model) {
model.addAttribute("persons", personService.getAllPersons());
model.addAttribute("appName", appName);
model.addAttribute("appVersion", appVersion);
model.addAttribute("maxPersons", maxPersons);
return "persons-list";
}
}
3.3 Default-Werte setzen
@Value("${app.max-persons:50}") // Default: 50
private int maxPersons;
@Value("${app.features.email-enabled:false}") // Default: false
private boolean emailEnabled;
Wenn Property nicht existiert → Default-Wert wird genommen!
3.4 Im Template anzeigen
persons-list.html:
<body>
<h1 th:text="${appName}">Persons Management System</h1>
<p style="color: #666; font-size: 12px;">
Version <span th:text="${appVersion}">1.0.0</span> |
Max. Personen: <span th:text="${maxPersons}">100</span>
</p>
<!-- Rest wie gehabt -->
</body>
Schritt 4: @ConfigurationProperties – Typsicher & sauber!
4.1 Das Problem mit @Value
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String appVersion;
@Value("${app.max-persons}")
private int maxPersons;
@Value("${app.features.email-enabled}")
private boolean emailEnabled;
@Value("${app.features.export-enabled}")
private boolean exportEnabled;
Das wird schnell unübersichtlich! 😵
4.2 Die Lösung: @ConfigurationProperties
Erstelle: src/main/java/.../config/AppProperties.java
package com.example.helloworldapi.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;
@Component
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
private String name;
private String version;
private int maxPersons;
private Features features = new Features();
@Data
public static class Features {
private boolean emailEnabled;
private boolean exportEnabled;
}
}
application.properties (wie vorher):
app.name=Persons Management System app.version=1.0.0 app.max-persons=100 app.features.email-enabled=true app.features.export-enabled=false
4.3 Im Controller nutzen
PersonViewController.java:
@Controller
@RequiredArgsConstructor
public class PersonViewController {
private final PersonService personService;
private final AppProperties appProperties; // Injizieren!
@GetMapping("/persons")
public String showPersons(Model model) {
model.addAttribute("persons", personService.getAllPersons());
model.addAttribute("appName", appProperties.getName());
model.addAttribute("appVersion", appProperties.getVersion());
model.addAttribute("maxPersons", appProperties.getMaxPersons());
return "persons-list";
}
}
Vorteile:
- ✅ Typsicher (IDE hilft)
- ✅ Übersichtlich
- ✅ Validation möglich
- ✅ Verschachtelung einfach
- ✅ Besser testbar
4.4 Dependency hinzufügen (falls noch nicht vorhanden)
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Schritt 5: Logging verstehen
5.1 Was ist Logging?
Logging = Nachrichten aufzeichnen während die App läuft
Beispiel OHNE Logging:
public Person createPerson(Person person) {
person.setId(idCounter.getAndIncrement());
persons.add(person);
return person;
}
Wenn etwas schiefgeht → Keine Ahnung was passiert ist! 😱
Beispiel MIT Logging:
private static final Logger log = LoggerFactory.getLogger(PersonService.class);
public Person createPerson(Person person) {
log.debug("Creating new person: {} {}", person.getFirstname(), person.getLastname());
person.setId(idCounter.getAndIncrement());
persons.add(person);
log.info("Person created successfully with ID: {}", person.getId());
return person;
}
Jetzt sehen wir genau was passiert! ✅
5.2 Die drei großen Logging-Frameworks
In Java gibt es 3 wichtige Logging-Frameworks:
| Framework | Beschreibung | Wann nutzen? |
|---|---|---|
| JUL | Java Util Logging (java.util.logging) | Im JDK enthalten, veraltet |
| Log4j2 | Apache Log4j 2 | Sehr performant, async logging |
| Logback | Nachfolger von Log4j 1.x | Spring Boot Standard! |
Vergleichstabelle (wichtig für Multiple Choice!):
| Feature | JUL | Log4j2 | Logback |
|---|---|---|---|
| Im JDK dabei | ✅ | ❌ | ❌ |
| Spring Boot Standard | ❌ | ❌ | ✅ |
| Performance | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Async Logging | ❌ | ✅ | ✅ |
| Remote Logging | ❌ | ✅ (nativ) | ✅ (via Appender) |
| Garbage-Free | ❌ | ✅ | ❌ |
| Lambda Support | ❌ | ✅ | ❌ |
| Konfiguration | Kompliziert | XML/JSON/YAML | XML/Properties |
| SLF4J Support | Via Adapter | Via Adapter | Nativ ✅ |
| Beliebt | ❌ (veraltet) | ✅ (Enterprise) | ✅ (Standard) |
Warum welches Framework?
| Szenario | Framework | Grund |
|---|---|---|
| Spring Boot App (normal) | Logback | Ist schon dabei, reicht für 90% |
| Microservices (viele Services) | Log4j2 | Remote Logging zu ELK Stack |
| High-Performance (Trading, Gaming) | Log4j2 | Garbage-Free, schneller |
| Legacy Java App | JUL | Nur wenn nichts anderes geht |
| Verteilte Systeme | Log4j2 | Zentrale Log-Aggregation |
Was ist SLF4J?
SLF4J = Simple Logging Facade for Java
SLF4J ist KEINE Logging-Implementierung, sondern eine Abstraktionsschicht!
Dein Code
↓
SLF4J (Facade/Interface)
↓
┌───────┬───────────┬──────────┐
JUL Log4j2 Logback
Vorteil: Du programmierst gegen SLF4J → Kannst später die Implementierung wechseln ohne Code zu ändern!
// ✅ RICHTIG - SLF4J Interface import org.slf4j.Logger; import org.slf4j.LoggerFactory; // Spring Boot nutzt automatisch Logback als Implementierung private static final Logger log = LoggerFactory.getLogger(MyClass.class);
5.3 SLF4J nutzen (Standard in Spring Boot)
PersonService.java:
package com.example.helloworldapi.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
@Service
public class PersonService {
// Logger erstellen mit SLF4J
private static final Logger log = LoggerFactory.getLogger(PersonService.class);
private final List<Person> persons = new ArrayList<>();
private final AtomicLong idCounter = new AtomicLong(1);
public PersonService() {
log.info("PersonService initialized");
}
public List<Person> getAllPersons() {
log.debug("Getting all persons, current count: {}", persons.size());
return persons;
}
public Person getPersonById(Long id) {
log.debug("Looking for person with ID: {}", id);
Person person = persons.stream()
.filter(p -> p.getId().equals(id))
.findFirst()
.orElse(null);
if (person == null) {
log.warn("Person with ID {} not found!", id);
} else {
log.debug("Found person: {} {}", person.getFirstname(), person.getLastname());
}
return person;
}
public Person createPerson(Person person) {
log.info("Creating new person: {} {}", person.getFirstname(), person.getLastname());
person.setId(idCounter.getAndIncrement());
persons.add(person);
log.info("Person created successfully with ID: {}", person.getId());
log.debug("Total persons now: {}", persons.size());
return person;
}
}
5.4 Log-Level verstehen
| Level | Wann nutzen? | Beispiel |
|---|---|---|
| TRACE | Sehr detailliert (fast nie) | „Entering method calculateTax()“ |
| DEBUG | Entwicklung/Debugging | „User input: firstname=Max“ |
| INFO | Normale Events | „Person created with ID 5“ |
| WARN | Warnung (nicht kritisch) | „Cache is 90% full“ |
| ERROR | Fehler (App läuft weiter) | „Failed to send email“ |
Faustregel:
- Development: DEBUG
- Production: INFO oder WARN
5.5 Logs sehen
Starte die App:
mvn spring-boot:run -Dspring-boot.run.profiles=dev
Console-Output:
10:30:45.123 INFO 12345 --- [main] c.e.h.service.PersonService : PersonService initialized 10:30:45.124 DEBUG 12345 --- [main] c.e.h.service.PersonService : Getting all persons, current count: 0
Jetzt siehst du genau was passiert! 🎉
Was bedeutet die Ausgabe?
10:30:45.123 INFO 12345 --- [main] c.e.h.service.PersonService : Message here
↑ ↑ ↑ ↑ ↑ ↑
Timestamp Level PID Thread Logger (Klassenname) Nachricht
🟡 PROFESSIONAL
Schritt 6: Logging konfigurieren
6.1 Log-Level pro Package
application-dev.properties:
# Logging für Development logging.level.root=INFO logging.level.com.example.helloworldapi=DEBUG logging.level.org.springframework.web=DEBUG logging.level.org.hibernate=INFO logging.level.org.hibernate.SQL=DEBUG
application-prod.properties:
# Logging für Production logging.level.root=WARN logging.level.com.example.helloworldapi=INFO logging.level.org.springframework=WARN
6.2 Log-Pattern anpassen
application.properties:
# Log-Pattern
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
Was bedeutet das?
%d{...}= Datum/Zeit[%thread]= Thread-Name%-5level= Log-Level (LEFT-aligned, 5 Zeichen)%logger{36}= Logger-Name (max 36 Zeichen)%msg= Die eigentliche Nachricht%n= Newline
Output:
2025-10-17 10:30:45.123 [main] INFO c.e.h.service.PersonService - Person created successfully with ID: 1
6.3 Logs in Datei schreiben
application-prod.properties:
# Logging in Datei logging.file.name=logs/persons-app.log logging.file.max-size=10MB logging.file.max-history=30 logging.level.root=WARN logging.level.com.example.helloworldapi=INFO
Erstelle Ordner:
mkdir logs
Starte App:
mvn spring-boot:run -Dspring-boot.run.profiles=prod
Prüfe Log-Datei:
cat logs/persons-app.log
Schritt 7: Praktisches Logging-Beispiel
PersonViewController mit Logging:
package com.example.helloworldapi.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import lombok.RequiredArgsConstructor;
@Controller
@RequiredArgsConstructor
public class PersonViewController {
private static final Logger log = LoggerFactory.getLogger(PersonViewController.class);
private final PersonService personService;
private final AppProperties appProperties;
@GetMapping("/persons")
public String showPersons(Model model) {
log.debug("Showing persons list");
List<Person> persons = personService.getAllPersons();
log.info("Displaying {} persons", persons.size());
model.addAttribute("persons", persons);
model.addAttribute("appName", appProperties.getName());
return "persons-list";
}
@GetMapping("/persons/{id}")
public String showPersonDetails(@PathVariable Long id, Model model) {
log.debug("Showing details for person ID: {}", id);
Person person = personService.getPersonById(id);
if (person == null) {
log.warn("Person with ID {} not found, redirecting to list", id);
return "redirect:/persons";
}
log.debug("Displaying person: {} {}", person.getFirstname(), person.getLastname());
model.addAttribute("person", person);
return "person-details";
}
}
🔵 BONUS: ENTERPRISE FEATURES
Schritt 8: Secrets & Umgebungsvariablen
8.1 Das Problem
NIEMALS so:
# ❌ FALSCH! app.api.key=geheimer-api-key-123 app.admin.password=admin123
Git → GitHub → Jeder kann’s sehen!
8.2 Die Lösung: Umgebungsvariablen
application-prod.properties:
# Externe API-Keys (Beispiel)
app.api.key=${API_KEY}
app.api.secret=${API_SECRET}
# Admin Credentials
app.admin.username=${ADMIN_USERNAME}
app.admin.password=${ADMIN_PASSWORD}
Beim Start setzen:
export API_KEY=dein-geheimer-key export API_SECRET=dein-geheimes-secret export ADMIN_USERNAME=admin export ADMIN_PASSWORD=geheim123 java -jar target/persons-app.jar --spring.profiles.active=prod
8.3 Default-Werte für Dev
application-dev.properties:
# In Dev nutzen wir Dummy-Werte
app.api.key=${API_KEY:dev-dummy-key}
app.api.secret=${API_SECRET:dev-dummy-secret}
app.admin.username=${ADMIN_USERNAME:dev-admin}
app.admin.password=${ADMIN_PASSWORD:dev123}
Wenn Umgebungsvariablen NICHT gesetzt → Dummy-Werte werden genutzt!
Schritt 9: Bootstrap-Klasse für Test-Daten
9.1 Was ist ein Bootstrap?
Bootstrap = Klasse die beim App-Start Initial-Daten lädt
Warum?
- Ohne Datenbank brauchen wir trotzdem Daten zum Testen
- Daten sollen beim Start automatisch da sein
- Verschiedene Test-Daten für dev/prod möglich
9.2 Bootstrap-Klasse erstellen
Erstelle: src/main/java/.../bootstrap/DataBootstrap.java
package com.example.helloworldapi.bootstrap;
import com.example.helloworldapi.model.Person;
import com.example.helloworldapi.service.PersonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component
@Profile("dev") // Nur in DEV-Profil!
@RequiredArgsConstructor
public class DataBootstrap implements CommandLineRunner {
private static final Logger log = LoggerFactory.getLogger(DataBootstrap.class);
private final PersonService personService;
@Override
public void run(String... args) throws Exception {
log.info("Starting DataBootstrap...");
loadPersons();
log.info("DataBootstrap completed! Loaded {} persons",
personService.getAllPersons().size());
}
private void loadPersons() {
log.debug("Loading test persons...");
// Test-Person 1
Person person1 = new Person();
person1.setFirstname("Max");
person1.setLastname("Mustermann");
person1.setEmail("max@example.com");
personService.createPerson(person1);
// Test-Person 2
Person person2 = new Person();
person2.setFirstname("Anna");
person2.setLastname("Schmidt");
person2.setEmail("anna@example.com");
personService.createPerson(person2);
log.info("Loaded 2 test persons");
}
}
Was macht das?
| Annotation/Interface | Bedeutung |
|---|---|
@Component | Spring verwaltet diese Klasse |
@Profile("dev") | Nur in DEV-Profil aktiv! |
CommandLineRunner | run() wird beim App-Start aufgerufen |
@RequiredArgsConstructor | Constructor Injection (Lombok) |
9.3 PersonService anpassen
Entferne die Test-Daten aus dem Constructor!
PersonService.java:
@Service
public class PersonService {
private static final Logger log = LoggerFactory.getLogger(PersonService.class);
private final List<Person> persons = new ArrayList<>();
private final AtomicLong idCounter = new AtomicLong(1);
public PersonService() {
log.info("PersonService initialized");
// KEINE Test-Daten mehr hier!
}
// Rest der Methoden bleiben gleich...
}
9.4 Testen
Dev-Profil (mit Test-Daten):
mvn spring-boot:run -Dspring-boot.run.profiles=dev
Console zeigt:
10:30:45.123 INFO c.e.h.service.PersonService : PersonService initialized 10:30:45.125 INFO c.e.h.bootstrap.DataBootstrap : Starting DataBootstrap... 10:30:45.133 INFO c.e.h.bootstrap.DataBootstrap : Loaded 2 test persons
Öffne: http://localhost:8080/persons → 2 Personen sind da! ✅
Schritt 10: Bonus – Logback-Konfiguration (Optional)
Erstelle: src/main/resources/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Console Appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- File Appender -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/persons-app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/persons-app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Root Logger -->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
<!-- Deine App: DEBUG -->
<logger name="com.example.helloworldapi" level="DEBUG" />
</configuration>
Jetzt gehen Logs zu Console UND Datei!
✅ Checkpoint: Hast du Tag 5 geschafft?
Grundlagen (🟢):
- [ ] application.properties existiert und funktioniert
- [ ] Profile (dev, prod) sind angelegt
- [ ] Du kannst Profile wechseln
- [ ] @Value funktioniert
- [ ] @ConfigurationProperties sind erstellt
- [ ] Logging ist im PersonService implementiert
- [ ] Log-Level verstanden (DEBUG, INFO, WARN, ERROR)
Professional (🟡):
- [ ] Log-Level pro Profil eingestellt
- [ ] Logs werden in Datei geschrieben (prod)
- [ ] Logging ist im PersonViewController implementiert
- [ ] Log-Pattern angepasst
Bonus (🔵):
- [ ] Umgebungsvariablen für Secrets funktionieren
- [ ] Bootstrap-Klasse lädt Test-Daten
- [ ] Bootstrap läuft nur im dev-Profil
- [ ] Logback-XML konfiguriert (optional)
Alles ✅? Du bist bereit für Tag 6!
Nicht alles funktioniert? → Schau in die Troubleshooting-Sektion!
🆘 Troubleshooting: Die häufigsten Probleme
Problem 1: Profile wird nicht geladen
Symptom: Änderungen in application-dev.properties haben keine Wirkung
Lösung:
# Prüfe welches Profil aktiv ist mvn spring-boot:run -Dspring-boot.run.profiles=dev # In Logs schauen: # "The following profiles are active: dev"
Problem 2: Property nicht gefunden
Symptom:
Could not resolve placeholder 'app.name' in value "${app.name}"
Lösung:
# Prüfe Schreibweise! app.name=Persons Management System # NICHT app-name oder app_name
Problem 3: @ConfigurationProperties funktioniert nicht
Symptom: Properties sind null
Lösung 1: @Component vergessen?
@Component // MUSS da sein!
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
// ...
}
Lösung 2: Dependency fehlt?
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Problem 4: Logs erscheinen nicht
Symptom: Logger schreibt nichts
Ursache 1: Log-Level zu hoch
# application.properties logging.level.com.example.helloworldapi=DEBUG # Nicht INFO oder WARN!
Ursache 2: Logger falsch importiert
// ❌ FALSCH import java.util.logging.Logger; // ✅ RICHTIG import org.slf4j.Logger; import org.slf4j.LoggerFactory;
Problem 5: Bootstrap läuft nicht
Symptom: Keine Test-Daten beim Start
Lösung:
# Bootstrap läuft nur in dev! mvn spring-boot:run -Dspring-boot.run.profiles=dev
Hier sind noch einige externe Links, die sich hervorragend zum Thema „Konfiguration & Logging in Spring Boot“ eignen — mit guten Erklärungen, Beispielen und Praxisbezug damit kannst du dein Wissen noch mehr vertiefen:
- „Logging :: Spring Boot” — offizielle Dokumentation von Spring Boot zu Logging und Konfiguration. Home+1
- „Logging in Spring Boot – Baeldung” — ein ausführlicher Artikel über Logging-Frameworks (Logback, Log4j2) in Spring Boot. Baeldung on Kotlin
- „Spring Boot – Logging | GeeksforGeeks” — Einsteigerfreundlicher Artikel mit Beispielen zur Konfiguration über
application.propertiesund Logging in Dateien. GeeksforGeeks+1 - „A Guide to Spring Boot Logging: Best Practices & Techniques” — Blogbeitrag mit Überblick über Best Practices beim Logging in Spring Boot-Anwendungen. Last9
- „How to Configure Default Log Files – Spring Boot Logging” — Praxisanleitung zum Einrichten von Logdateien, statt nur Konsolenausgabe. signoz.io
🔥 Elyndras Real Talk:
Nova kam heute zu mir und fragte: „Elyndra, warum machen wir das so kompliziert mit Profilen? Kann ich nicht einfach eine properties-Datei haben?“
Ich musste schmunzeln – genau die Frage hatte ich vor 5 Jahren auch gestellt!
Meine Antwort: „Stell dir vor, du entwickelst lokal mit Thymeleaf-Cache AUS auf Port 8080. Dann deployest du auf den Test-Server – Cache AN, Port 80, andere Log-Level. Dann kommt Production – wieder andere Settings, Logging in Dateien statt Console. Willst du wirklich jedes Mal die properties-Datei händisch ändern und hoffen, dass du nichts vergisst?“
Nova nickte: „Okay, verstehe. Aber warum Logging auf DEBUG in Dev und INFO in Prod?“
Code Sentinel, der gerade vorbeikam, warf ein: „Weil du in Production nicht jeden einzelnen Request-Parameter in deinen Logs haben willst. Das sind Gigabytes an Daten! Und Performance-Killer. In Dev willst du aber ALLES sehen, um Bugs zu finden.“
Ich ergänzte: „Genau! Und noch was – in Dev loggst du nach Console, in Prod in Dateien mit Rotation. Sonst hast du nach 3 Monaten eine 50GB-Log-Datei und dein Server ist voll.“
Das ist der Unterschied zwischen Junior und Senior Developer: Nicht nur Features bauen, sondern auch an verschiedene Umgebungen, Wartbarkeit und Fehlerquellen denken!
❓ FAQ (Häufige Fragen)
Q: Warum application.properties und nicht application.yml?
A: Das ist unser Standard in diesem Kurs! Properties ist einfacher für Anfänger und hat keine Whitespace-Probleme wie YAML.
Q: Wie viele Profile sollte ich haben?
A: Mindestens 2 (dev, prod). Optional: test, staging, local. Nicht übertreiben!
Q: Sollte ich logback-spring.xml nutzen oder application.properties?
A: Für die meisten Fälle reicht application.properties. Nur bei komplexen Anforderungen lohnt sich logback-spring.xml.
Q: Was ist der Unterschied zwischen JUL, Log4j2 und Logback?
A: JUL = Im JDK enthalten, veraltet. Log4j2 = Sehr performant, Remote Logging, Garbage-Free. Logback = Spring Boot Standard, gute Balance.
Q: Warum benutzt Spring Boot Logback und nicht Log4j2?
A: Logback ist „gut genug“ für die meisten Apps und hat native SLF4J-Unterstützung. Log4j2 ist performanter (Remote Logging, Garbage-Free), aber meist nicht nötig.
Q: Wann sollte ich Log4j2 statt Logback nutzen?
A: Microservices (zentrale Logs mit ELK Stack), High-Performance (Garbage-Free), Lambda-Support. Für normale Apps reicht Logback.
Q: Was ist SLF4J genau?
A: SLF4J ist KEINE Logging-Implementierung, sondern eine Abstraktionsschicht. Du programmierst gegen SLF4J-Interfaces, Spring Boot nutzt Logback als Implementierung.
Q: Welches Log-Level für Production?
A: INFO oder WARN für root. DEBUG nur für deine eigene App wenn du Probleme debuggen musst.
Q: Wo speichere ich Secrets?
A: Umgebungsvariablen, Vault, Cloud Secrets Manager. NIEMALS im Code oder Git!
📅 Nächster Kurstag: Tag 6
Morgen im Kurs / Nächster Blogbeitrag:
„DI & AOP im Detail – Dependency Injection & Aspektorientierte Programmierung“
Was du lernen wirst:
- Wie funktioniert Dependency Injection wirklich?
- @Autowired, @Qualifier, @Primary verstehen
- Constructor Injection vs Field Injection
- AOP-Grundlagen mit @Aspect
- Custom Annotations erstellen
- Cross-Cutting Concerns (Logging, Security, etc.)
Voraussetzung: Tag 5 abgeschlossen
👉 Zum Blogbeitrag Tag 6 (erscheint morgen)
📚 Deine Fortschritts-Übersicht
| Tag | Thema | Status |
|---|---|---|
| ✅ 1 | Erste REST API | ABGESCHLOSSEN! 🎉 |
| ✅ 2 | Spring Container & DI | ABGESCHLOSSEN! 🎉 |
| ✅ 3 | @Controller & Thymeleaf Basics | ABGESCHLOSSEN! 🎉 |
| ✅ 4 | Thymeleaf Forms & MVC-Pattern | ABGESCHLOSSEN! 🎉 |
| ✅ 5 | Konfiguration & Logging | ABGESCHLOSSEN! 🎉 |
| → 6 | DI & AOP im Detail | Als nächstes |
| 7 | Scopes in Spring | Noch offen |
| 8 | WebSockets | Noch offen |
| 9 | JAX-RS in Spring Boot | Noch offen |
| 10 | Integration & Abschluss | Noch offen |
Du hast 50% des Kurses geschafft! 💪
Alle Blogbeiträge dieser Serie:
👉 Spring Boot Basic – Komplette Übersicht
📥 Download & Ressourcen
Projekt zum Download:
👉 SpringBootConfig-v1.0.zip (Stand: 17.10.2025)
Was ist im ZIP enthalten:
- ✅ Komplettes Maven-Projekt
- ✅ application.properties mit Profilen (dev, prod)
- ✅ @ConfigurationProperties Beispiel
- ✅ Vollständiges Logging in Service & Controller
- ✅ Bootstrap-Klasse für Test-Daten
- ✅ Umgebungsvariablen-Support
- ✅ logback-spring.xml Beispiel
- ✅ README mit Schnellstart
Projekt starten:
# ZIP entpacken # In NetBeans öffnen: File → Open Project # Development-Modus: mvn spring-boot:run -Dspring-boot.run.profiles=dev # Production-Modus: mvn spring-boot:run -Dspring-boot.run.profiles=prod
Probleme? Issue melden oder schreib mir: elyndra@java-developer.online
Das war Tag 5 von Spring Boot Basic!
Du kannst jetzt:
- ✅ application.properties komplett nutzen
- ✅ Profile für verschiedene Umgebungen einsetzen
- ✅ @Value und @ConfigurationProperties verwenden
- ✅ SLF4J-Logging professionell nutzen
- ✅ Log-Level pro Umgebung konfigurieren
- ✅ Logs in Dateien schreiben
- ✅ Secrets sicher mit Umgebungsvariablen verwalten
- ✅ Bootstrap-Klassen für Initial-Daten erstellen
- ✅ Das komplette Konfigurationssystem verstehen!
Morgen: Dependency Injection & AOP im Detail! 🚀
Keep coding, keep learning! 💚
Tag 6 erscheint morgen. Bis dahin: Happy Coding!
Tags: #SpringBoot #Configuration #Logging #Properties #Profiles #Tag5

