Spring Boot Aufbau-Kurs – Tag 1 von 10
Von Elyndra Valen, Senior Entwicklerin bei Java Fleet Systems Consulting

🗺️ Deine Position im Kurs
| Tag | Thema | Status |
|---|---|---|
| → 1 | Auto-Configuration & Custom Starter | 👉 DU BIST HIER! |
| 2 | Spring Data JPA Basics | 📜 Kommt als nächstes |
| 3 | JPA Relationships & Queries | 🔒 Noch nicht freigeschaltet |
| 4 | Spring Security – Part 1 | 🔒 Noch nicht freigeschaltet |
| 5 | Spring Security – Part 2 | 🔒 Noch nicht freigeschaltet |
| 6 | Caching & Serialisierung | 🔒 Noch nicht freigeschaltet |
| 7 | Messaging & Email | 🔒 Noch nicht freigeschaltet |
| 8 | Testing & Dokumentation | 🔒 Noch nicht freigeschaltet |
| 9 | Spring Boot Actuator | 🔒 Noch nicht freigeschaltet |
| 10 | Template Engines & Microservices | 🔒 Noch nicht freigeschaltet |
Modul: Spring Boot Aufbau-Kurs (10 Arbeitstage)
Gesamt-Dauer: 10 Arbeitstage (je 8 Stunden)
Dein Ziel: Die Spring Boot „Magie“ verstehen & deinen eigenen Starter bauen
📋 Voraussetzungen für diesen Tag
Du brauchst:
- ✅ Java SE Grundlagen (40 Tage) abgeschlossen
- ✅ Java Web Basic + Aufbau (20 Tage) abgeschlossen
- ✅ Spring Boot Basic (10 Tage) abgeschlossen
- ✅ Du verstehst REST APIs, Dependency Injection und Maven
Tag verpasst oder später eingestiegen?
Kein Problem! Dieser Blogbeitrag deckt genau den Stoff von Tag 1 ab. Du kannst das komplette Projekt unten herunterladen und es in deinem eigenen Tempo durcharbeiten!
⚡ Kurze Zusammenfassung – Das Wichtigste in 30 Sekunden
Heute lüften wir das Geheimnis hinter Spring Boot’s „Magie“: Du baust einen eigenen Custom Starter (greeting-spring-boot-starter), der automatisch einen Service bereitstellt, der über application.properties konfigurierbar ist – genau wie spring-boot-starter-web oder andere offizielle Starter!
Du lernst heute:
- ✅
@ConfigurationPropertiesfür typsichere Konfiguration - ✅
@AutoConfigurationmit Conditional-Annotations - ✅
spring.factoriesfür die Registrierung deines Starters - ✅ Die drei Säulen jedes Starters: Dependencies, Auto-Configuration, Properties
Am Ende des Tages: Du verstehst wie Spring Boot „denkt“ und kannst eigene wiederverwendbare Starter für deine Projekte bauen!
💻 Was du heute baust:
Heute bauen wir gemeinsam einen greeting-spring-boot-starter – einen vollwertigen Custom Starter, der automatisch einen GreetingService bereitstellt. Dabei lüften wir das Geheimnis, wie Spring Boot seine „Magie“ macht: Properties aus application.properties werden automatisch gebunden, Beans werden conditional erstellt, und alles funktioniert ohne dass du etwas konfigurieren musst!
🎯 Dein Lernpfad heute:
Du arbeitest heute in mehreren aufbauenden Schwierigkeitsstufen. Arbeite in deinem eigenen Tempo durch die Schritte:
🟢 GRUNDLAGEN (Schritte 1-6)
Was du lernst:
- Das Mysterium hinter Spring Boot verstehen
- Projekt-Struktur für einen Custom Starter aufbauen
- Service Interface und Implementierung erstellen
@ConfigurationPropertiesfür typsichere Konfiguration nutzen@AutoConfigurationund Conditionals verstehen- Den Starter via
spring.factoriesregistrieren
Ziel: Du hast einen funktionierenden Custom Starter, der automatisch einen Service bereitstellt und über Properties konfigurierbar ist.
Zeitaufwand: Ca. 4-5 Stunden
🟡 PROFESSIONALS (Schritte 7-8)
Was du lernst:
- Den Starter in einem Test-Projekt einsetzen
- Debug-Modus nutzen um Auto-Configuration zu analysieren
- Conditions Evaluation Report verstehen
Ziel: Du weißt wie du Starter testest, debuggst und in Production einsetzt.
Zeitaufwand: Ca. 2 Stunden
🔵 BONUS: Advanced Features (Schritt 9)
Was du baust:
- Eigene Implementierung überschreiben (Überschreibbarkeit)
- Nested Properties für komplexe Konfigurationen
- Advanced Conditional-Szenarien
Ziel: Du beherrschst fortgeschrittene Starter-Features für Enterprise-Anwendungen.
Zeitaufwand: Ca. 1-2 Stunden (optional)
💡 Tipp: Die Grundlagen (Schritte 1-6) sind essenziell – ohne sie verstehst du nicht, wie Spring Boot funktioniert. Professional (🟡) ist für alle wichtig, die produktionsreifen Code schreiben. Bonus (🔵) ist perfekt wenn du eigene komplexe Starter entwickeln möchtest oder einfach neugierig bist!
🟢 GRUNDLAGEN
Schritt 1: Das Mysterium verstehen
Hi! 👋
Elyndra hier – und heute tauchen wir gemeinsam in die Tiefen von Spring Boot ein.
Kennst du das Gefühl? Du fügst spring-boot-starter-web zu deinem Projekt hinzu und plötzlich:
- Tomcat startet wie von Geisterhand
- Jackson serialisiert JSON automatisch
- Error Pages funktionieren einfach
- Alles läuft – ohne eine Zeile Konfiguration!
„Das ist doch Magie!“ hörte ich letzte Woche von Nova. Und weißt du was? Sie hatte recht – es fühlt sich wie Magie an. Aber wie bei guter Magie steckt dahinter ein elegantes System, das wir heute entschlüsseln.
Die drei Säulen der Spring Boot „Magie“
Jeder Starter basiert auf drei Prinzipien:
1. Dependencies – Die benötigten Libraries werden mitgebracht
Wenn du spring-boot-starter-web hinzufügst, bekommst du automatisch Tomcat, Jackson, Spring MVC und alles was du brauchst. Du musst nicht jede Dependency einzeln hinzufügen!
2. Auto-Configuration – Beans werden automatisch erstellt
Spring Boot analysiert deinen Classpath und erstellt automatisch die richtigen Beans. Tomcat da? → Webserver wird konfiguriert. Jackson da? → JSON-Serialisierung läuft.
3. Properties – Konfiguration erfolgt deklarativ über application.properties
Statt Java-Code zu schreiben, schreibst du einfach server.port=8080 und Spring Boot versteht es.
Das ist wie ein gut organisiertes Werkzeugset: Alles was du brauchst ist dabei, nichts fehlt, nichts ist zu viel.
Unser Lernprojekt: greeting-spring-boot-starter
Heute bauen wir einen Starter, der so funktioniert:
// Du schreibst nur:
@Autowired
private GreetingService greetingService;
String greeting = greetingService.greet("Anna");
// Output: "Hello, Anna!"
Konfigurierbar über application.properties:
greeting.message=Guten Tag greeting.uppercase=true greeting.prefix=[VIP] # Output wird: "[VIP] GUTEN TAG, ANNA!"
Das Schöne: Wir bauen das Schritt für Schritt nach und du verstehst dabei, wie Spring Boot „denkt“.
Schritt 2: Projekt-Struktur aufsetzen
Lass uns strukturiert vorgehen – wie beim Refactoring von Legacy-Code: Erst die Architektur verstehen, dann implementieren.
Maven Projekt erstellen
Unsere Projekt-Struktur wird so aussehen:
greeting-spring-boot-starter/
├── pom.xml
└── src/main/java/com/javafleet/greeting/
├── GreetingService.java
├── DefaultGreetingService.java
├── GreetingProperties.java
└── GreetingAutoConfiguration.java
└── src/main/resources/META-INF/spring/
└── org.springframework.boot.autoconfigure.AutoConfiguration.imports
Warum diese Struktur? Jede Klasse hat eine klare Verantwortung – Single Responsibility Principle in Aktion!
- GreetingService.java – Das Interface (der Vertrag)
- DefaultGreetingService.java – Die Standard-Implementierung
- GreetingProperties.java – Konfiguration aus
application.properties - GreetingAutoConfiguration.java – Die Auto-Configuration-Logik
- AutoConfiguration.imports – Registrierung des Starters (Spring Boot 3!)
Die pom.xml (Spring Boot 3!)
Erstelle ein neues Maven-Projekt mit dieser pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javafleet</groupId>
<artifactId>greeting-spring-boot-starter</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Greeting Spring Boot Starter</name>
<description>Auto-configures a GreetingService</description>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.2.0</spring-boot.version>
</properties>
<dependencies>
<!-- Spring Boot Auto-Configuration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Configuration Properties Processor - Das ist wichtig! -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Wichtig für Spring Boot 3:
- ✅ Minimum Java 17
- ✅ Spring Boot 3.2.0 oder höher
- ✅
spring-boot-configuration-processorfür IDE Auto-Complete (gleich siehst du warum!)
💡 Tipp: Speichere die pom.xml und führe in deiner IDE „Maven → Reload Project“ aus, damit alle Dependencies heruntergeladen werden.
Schritt 3: Das Service Interface
Beginnen wir mit dem einfachsten Teil – dem Interface. Das ist wie das Fundament eines Hauses: solide und klar definiert.
GreetingService.java
Erstelle die Datei src/main/java/com/javafleet/greeting/GreetingService.java:
package com.javafleet.greeting;
/**
* Service für Begrüßungen.
* Wird automatisch von der Auto-Configuration bereitgestellt.
*/
public interface GreetingService {
/**
* Erstellt eine Begrüßung für den angegebenen Namen.
*
* @param name Der zu begrüßende Name
* @return Die formatierte Begrüßung
*/
String greet(String name);
}
Was macht dieses Interface?
- Es definiert den Vertrag für unseren Service
- Jede Implementierung muss die Methode
greet(String name)bereitstellen - Es ist bewusst einfach gehalten – später kannst du es erweitern!
💡 Zwischencheck: Hast du die Datei erstellt? Compiliert sie ohne Fehler? Gut! Weiter geht’s.
Schritt 4: Die Standard-Implementierung
Jetzt implementieren wir das Interface mit einer konkreten Klasse.
DefaultGreetingService.java
Erstelle die Datei src/main/java/com/javafleet/greeting/DefaultGreetingService.java:
package com.javafleet.greeting;
/**
* Standard-Implementierung des GreetingService.
* Diese Klasse wird automatisch von Spring Boot als Bean erstellt.
*/
public class DefaultGreetingService implements GreetingService {
private final GreetingProperties properties;
/**
* Constructor Injection - Best Practice in Spring!
* Die Properties werden automatisch injiziert.
*/
public DefaultGreetingService(GreetingProperties properties) {
this.properties = properties;
}
@Override
public String greet(String name) {
// Die Begrüßungs-Message aus den Properties holen
String message = properties.getMessage();
// Prefix hinzufügen wenn konfiguriert
if (properties.getPrefix() != null && !properties.getPrefix().isEmpty()) {
message = properties.getPrefix() + " " + message;
}
// Namen hinzufügen
String greeting = message + ", " + name + "!";
// Uppercase wenn konfiguriert
if (properties.isUppercase()) {
greeting = greeting.toUpperCase();
}
return greeting;
}
}
Was passiert hier?
- Constructor Injection: Wir nutzen Constructor Injection (Best Practice!) um die
GreetingPropertieszu bekommen - Properties nutzen: Die Konfiguration aus
application.propertiesfließt überGreetingPropertiesin unseren Service - Logik: Wir bauen die Begrüßung dynamisch zusammen – mit Prefix, Message, Name und optional Uppercase
Aber wo kommen die GreetingProperties her? Das machen wir jetzt!
💡 Zwischencheck: Die Klasse wird noch nicht kompilieren, weil GreetingProperties fehlt. Das ist normal! Weiter zum nächsten Schritt.
Schritt 5: Configuration Properties – Der Schlüssel zur Magie
Jetzt kommt der wichtigste Teil: Wie binden wir application.properties an Java-Klassen?
GreetingProperties.java
Erstelle die Datei src/main/java/com/javafleet/greeting/GreetingProperties.java:
package com.javafleet.greeting;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration Properties für den Greeting Starter.
* Alle Properties mit dem Prefix "greeting" werden automatisch gebunden.
*
* Beispiel in application.properties:
* greeting.message=Hello
* greeting.uppercase=true
* greeting.prefix=[VIP]
*/
@ConfigurationProperties(prefix = "greeting")
public class GreetingProperties {
/**
* Die Begrüßungs-Message. Standard: "Hello"
*/
private String message = "Hello";
/**
* Soll die Ausgabe in Großbuchstaben sein? Standard: false
*/
private boolean uppercase = false;
/**
* Optionaler Prefix vor der Message
*/
private String prefix = "";
// Getter und Setter
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isUppercase() {
return uppercase;
}
public void setUppercase(boolean uppercase) {
this.uppercase = uppercase;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}
Das ist die Magie! 🎩✨
Die Annotation @ConfigurationProperties(prefix = "greeting") sagt Spring Boot:
- „Suche in
application.propertiesnach Properties die mitgreeting.beginnen“ - „Binde sie automatisch an die Felder dieser Klasse“
- „Nutze die Setter-Methoden zum Setzen der Werte“
Beispiel:
# In application.properties greeting.message=Guten Tag greeting.uppercase=true greeting.prefix=[PREMIUM]
Spring Boot macht automatisch:
properties.setMessage("Guten Tag"); // greeting.message
properties.setUppercase(true); // greeting.uppercase
properties.setPrefix("[PREMIUM]"); // greeting.prefix
Default-Werte: Wenn keine Properties gesetzt sind, greifen die Default-Werte ("Hello", false, "").
💡 Zwischencheck: Jetzt sollte dein Code kompilieren! Wenn nicht, prüfe ob alle drei Klassen (Interface, Service, Properties) erstellt sind.
Schritt 6: Auto-Configuration – Das Herzstück
Jetzt kommt der spannendste Teil: Die Auto-Configuration! Hier entscheiden wir, wann und wie unser Service automatisch erstellt wird.
GreetingAutoConfiguration.java
Erstelle die Datei src/main/java/com/javafleet/greeting/GreetingAutoConfiguration.java:
package com.javafleet.greeting;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* Auto-Configuration für den Greeting Starter.
* Diese Klasse wird automatisch von Spring Boot geladen.
*/
@AutoConfiguration
@ConditionalOnClass(GreetingService.class)
@EnableConfigurationProperties(GreetingProperties.class)
public class GreetingAutoConfiguration {
/**
* Erstellt den GreetingService Bean.
*
* @ConditionalOnMissingBean: Nur erstellen wenn der User nicht bereits
* eine eigene Implementierung bereitgestellt hat
* @ConditionalOnProperty: Nur erstellen wenn nicht explizit disabled
*/
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "greeting",
name = "enabled",
havingValue = "true",
matchIfMissing = true
)
public GreetingService greetingService(GreetingProperties properties) {
return new DefaultGreetingService(properties);
}
}
Was passiert hier? Lass uns Schritt für Schritt durchgehen:
@AutoConfiguration
Diese Annotation sagt Spring Boot: „Ich bin eine Auto-Configuration-Klasse, lade mich automatisch beim Start!“
Das ist neu in Spring Boot 3 und ersetzt das alte @Configuration + @EnableAutoConfiguration.
@ConditionalOnClass(GreetingService.class)
Bedeutung: „Lade mich nur wenn GreetingService im Classpath ist“
Warum? Stell dir vor, jemand fügt deinen Starter als Dependency hinzu, aber hat die Library nicht richtig geladen. Ohne diese Annotation würde Spring Boot beim Start crashen. Mit dieser Annotation wird die Configuration einfach übersprungen wenn die Klasse fehlt.
@EnableConfigurationProperties(GreetingProperties.class)
Bedeutung: „Aktiviere die Configuration Properties und erstelle automatisch einen Bean für GreetingProperties„
Das sorgt dafür, dass Spring Boot:
- Die
GreetingPropertiesKlasse findet - Die Werte aus
application.propertiesbindet - Einen Bean erstellt den wir injizieren können
@Bean
Standard Spring Annotation: „Die Methode erstellt einen Bean der im Application Context verfügbar ist“
@ConditionalOnMissingBean
Das ist brilliant! 🎯
Bedeutung: „Erstelle diesen Bean nur wenn der User nicht bereits einen eigenen GreetingService Bean definiert hat“
Beispiel: Wenn ein User deinen Starter nutzt, aber seine eigene Implementierung haben will:
@Configuration
public class MyConfig {
@Bean
public GreetingService greetingService() {
return new MyCustomGreetingService(); // Eigene Implementierung!
}
}
Dann wird deine Default-Implementierung nicht geladen! Spring Boot merkt: „Oh, da gibt’s schon einen GreetingService Bean, ich muss keinen erstellen.“
Das nennt man Überschreibbarkeit – ein wichtiges Prinzip für gute Starter!
@ConditionalOnProperty
Bedeutung: „Erstelle diesen Bean nur unter bestimmten Property-Bedingungen“
Lass uns die Parameter durchgehen:
@ConditionalOnProperty(
prefix = "greeting", // Schaue bei "greeting.*" Properties
name = "enabled", // Konkret: "greeting.enabled"
havingValue = "true", // Muss "true" sein
matchIfMissing = true // WICHTIG: Was wenn Property fehlt?
)
Was heißt matchIfMissing = true?
- Wenn
greeting.enabledNICHT inapplication.propertiessteht: Bean wird erstellt ✅ - Wenn
greeting.enabled=truesteht: Bean wird erstellt ✅ - Wenn
greeting.enabled=falsesteht: Bean wird NICHT erstellt ❌
Das folgt dem Spring Boot Prinzip: Convention over Configuration
Der Starter soll out-of-the-box funktionieren, ohne dass du irgendwas konfigurieren musst. Aber du kannst ihn jederzeit mit greeting.enabled=false ausschalten!
💡 Zwischencheck:
- Hast du die Auto-Configuration erstellt?
- Verstehst du die Conditional-Annotations?
- Wenn ja → Weiter zum letzten Schritt der Grundlagen!
Schritt 7: Starter registrieren – spring.factories (Spring Boot 3!)
Fast geschafft! 🎉
Jetzt müssen wir Spring Boot nur noch sagen: „Hey, schau dir diese Auto-Configuration an!“
In Spring Boot 3 hat sich das Registrierungssystem geändert. Wir nutzen jetzt die Datei AutoConfiguration.imports statt spring.factories.
AutoConfiguration.imports erstellen
Erstelle die Datei:src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
Wichtig: Der komplette Pfad muss exakt so sein! META-INF/spring/ ist das neue Verzeichnis in Spring Boot 3.
Inhalt der Datei:
com.javafleet.greeting.GreetingAutoConfiguration
Das war’s! Diese eine Zeile sagt Spring Boot:
„Lade diese Auto-Configuration beim Start!“
Was passiert beim Start?
Wenn eine Spring Boot Anwendung startet:
- Spring Boot scannt alle JARs im Classpath
- Es sucht nach
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - Es lädt alle dort aufgelisteten Klassen
- Es prüft die
@Conditional...Annotations - Wenn alle Bedingungen erfüllt sind → Beans werden erstellt!
💡 Zwischencheck:
greeting-spring-boot-starter/
├── pom.xml
├── src/main/java/com/javafleet/greeting/
│ ├── GreetingService.java
│ ├── DefaultGreetingService.java
│ ├── GreetingProperties.java
│ └── GreetingAutoConfiguration.java
└── src/main/resources/META-INF/spring/
└── org.springframework.boot.autoconfigure.AutoConfiguration.imports
Hast du alle Dateien? Dann lass uns den Starter bauen!
Starter bauen & installieren
Öffne ein Terminal im Projekt-Verzeichnis und führe aus:
mvn clean install
Was passiert:
- Maven kompiliert deinen Code
- Erstellt ein JAR:
target/greeting-spring-boot-starter-1.0.0.jar - Installiert es in dein lokales Maven Repository (
~/.m2/repository/)
Gratulation! 🎉 Du hast soeben deinen ersten Custom Spring Boot Starter gebaut!
Aber funktioniert er auch? Das testen wir jetzt!
🟡 PROFESSIONALS
Schritt 8: Starter testen – Das Demo-Projekt
Jetzt wird’s spannend! Wir erstellen ein Test-Projekt um unseren Starter auszuprobieren.
Demo-Projekt erstellen
Erstelle ein neues Spring Boot Projekt (mit Spring Initializr oder manuell):
Struktur:
greeting-demo/
├── pom.xml
└── src/main/java/com/javafleet/demo/
└── DemoApplication.java
└── src/main/resources/
└── application.properties
pom.xml des Demo-Projekts
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<groupId>com.javafleet</groupId>
<artifactId>greeting-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Unser Custom Starter! -->
<dependency>
<groupId>com.javafleet</groupId>
<artifactId>greeting-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Spring Boot Starter für Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Wichtig: Wir fügen unseren Starter als Dependency hinzu! greeting-spring-boot-starter mit Version 1.0.0.
DemoApplication.java
package com.javafleet.demo;
import com.javafleet.greeting.GreetingService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
/**
* CommandLineRunner wird automatisch beim Start ausgeführt.
* Perfekt zum Testen!
*/
@Bean
public CommandLineRunner demo(GreetingService greetingService) {
return args -> {
// Test 1: Einfache Begrüßung
System.out.println(greetingService.greet("Franz"));
// Test 2: Mit anderem Namen
System.out.println(greetingService.greet("Nova"));
// Test 3: Mit Elyndra
System.out.println(greetingService.greet("Elyndra"));
};
}
}
Was passiert hier?
@SpringBootApplicationstartet Spring BootCommandLineRunnerist ein Interface das beim Start automatisch ausgeführt wird- Wir injizieren
GreetingService– ohne ihn selbst zu erstellen! - Spring Boot hat durch unseren Starter automatisch einen
GreetingServiceBean erstellt!
application.properties (leer lassen!)
# Erstmal keine Configuration - nutzen wir die Defaults
Starter testen – Test 1: Defaults
cd greeting-demo mvn spring-boot:run
Erwartete Ausgabe:
Hello, Franz! Hello, Nova! Hello, Elyndra!
Funktioniert’s? 🎉 Gratulation! Dein Starter arbeitet mit Default-Werten!
Funktioniert’s nicht?
- Prüfe ob
mvn clean installim Starter-Projekt erfolgreich war - Prüfe die Konsole auf Fehlermeldungen
- Stelle sicher dass die Dependency korrekt in der
pom.xmlsteht
Test 2: Properties konfigurieren
Jetzt probieren wir die Konfiguration aus!
Bearbeite application.properties:
greeting.message=Guten Tag greeting.uppercase=false greeting.prefix=
Starte neu:
mvn spring-boot:run
Erwartete Ausgabe:
Guten Tag, Franz! Guten Tag, Nova! Guten Tag, Elyndra!
Siehst du? Die Message hat sich geändert! 🎯
Test 3: Uppercase & Prefix
Bearbeite application.properties:
greeting.message=Willkommen greeting.uppercase=true greeting.prefix=[VIP]
Starte neu:
mvn spring-boot:run
Erwartete Ausgabe:
[VIP] WILLKOMMEN, FRANZ! [VIP] WILLKOMMEN, NOVA! [VIP] WILLKOMMEN, ELYNDRA!
Perfekt! 🚀 Alle drei Properties funktionieren!
Test 4: Starter deaktivieren
Bearbeite application.properties:
greeting.enabled=false
Starte neu:
mvn spring-boot:run
Erwartetes Ergebnis: Die Anwendung startet nicht!
Fehler:
*************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of method demo in com.javafleet.demo.DemoApplication required a bean of type 'com.javafleet.greeting.GreetingService' that could not be found.
Warum?
greeting.enabled=false→ Auto-Configuration lädt nicht → KeinGreetingServiceBeanDemoApplicationversuchtGreetingServicezu injizieren → Bean fehlt → Fehler!
Das ist korrekt! So funktioniert @ConditionalOnProperty – du kannst Features an/ausschalten!
💡 Tipp: Lösche die Zeile greeting.enabled=false wieder, damit die Tests weiterlaufen.
Schritt 9: Debug-Modus – Verstehe was Spring Boot macht
Jetzt kommt ein mächtiges Tool: Der Debug-Modus!
Debug aktivieren
Füge in application.properties hinzu:
debug=true greeting.message=Hello greeting.uppercase=false greeting.prefix=
Starte die Anwendung:
mvn spring-boot:run
Conditions Evaluation Report
Spring Boot gibt dir jetzt einen detaillierten Report in der Konsole:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
GreetingAutoConfiguration matched:
- @ConditionalOnClass found required class 'com.javafleet.greeting.GreetingService' (OnClassCondition)
GreetingAutoConfiguration#greetingService matched:
- @ConditionalOnMissingBean (types: com.javafleet.greeting.GreetingService; SearchStrategy: all) did not find any beans (OnBeanCondition)
- @ConditionalOnProperty (greeting.enabled=true) matched (OnPropertyCondition)
Negative matches:
-----------------
DataSourceAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.sql.DataSource' (OnClassCondition)
Was sagt uns das?
Positive matches = Diese Auto-Configurations wurden geladen:
- ✅
GreetingAutoConfigurationmatched – alle Bedingungen erfüllt! - ✅
@ConditionalOnClass–GreetingServicegefunden - ✅
@ConditionalOnMissingBean– Kein andererGreetingServiceBean existiert - ✅
@ConditionalOnProperty–greeting.enabledist true (oder fehlt)
Negative matches = Diese wurden NICHT geladen:
- ❌
DataSourceAutoConfiguration–DataSourceKlasse fehlt im Classpath
💡 Pro-Tipp: Nutze debug=true immer wenn:
- Deine Auto-Configuration nicht lädt
- Du verstehen willst warum ein Bean nicht erstellt wurde
- Du debuggen musst welche Conditionals nicht matchen
IDE Auto-Complete testen
Wenn du IntelliJ IDEA oder Eclipse nutzt, solltest du jetzt Auto-Complete für deine Properties haben!
Probier’s aus:
- Öffne
application.properties - Tippe
greeting.und warte - Die IDE sollte dir vorschlagen:
greeting.messagegreeting.uppercasegreeting.prefixgreeting.enabled
Warum funktioniert das?
Erinnerst du dich an spring-boot-configuration-processor in der pom.xml?
Dieser Processor:
- Scannt alle
@ConfigurationPropertiesKlassen - Generiert eine Datei:
META-INF/spring-configuration-metadata.json - IDEs lesen diese Datei und bieten Auto-Complete an!
Schaue dir die Datei an:target/classes/META-INF/spring-configuration-metadata.json
{
"properties": [
{
"name": "greeting.message",
"type": "java.lang.String",
"description": "Die Begrüßungs-Message.",
"defaultValue": "Hello"
},
{
"name": "greeting.uppercase",
"type": "java.lang.Boolean",
"description": "Soll die Ausgabe in Großbuchstaben sein?",
"defaultValue": false
},
{
"name": "greeting.prefix",
"type": "java.lang.String",
"description": "Optionaler Prefix vor der Message.",
"defaultValue": ""
}
]
}
Das ist Production-Ready! Professionelle Starter haben immer diese Metadata!
🔵 BONUS: Advanced Features
Gratulation! 🎉 Du hast die Grundlagen und Professional-Level gemeistert!
Jetzt zeige ich dir fortgeschrittene Features für Enterprise-Starter.
Bonus 1: Eigene Implementierung überschreiben
Erinnere dich an @ConditionalOnMissingBean? Lass uns das testen!
Eigene Implementierung erstellen
In greeting-demo erstellen:src/main/java/com/javafleet/demo/CustomGreetingService.java
package com.javafleet.demo;
import com.javafleet.greeting.GreetingService;
import org.springframework.stereotype.Service;
/**
* Eigene Implementierung - überschreibt den Default!
*/
@Service
public class CustomGreetingService implements GreetingService {
@Override
public String greet(String name) {
return "🎉 Custom Greeting: Hey " + name + ", you're awesome! 🎉";
}
}
Starte die Anwendung:
mvn spring-boot:run
Ausgabe:
🎉 Custom Greeting: Hey Franz, you're awesome! 🎉 🎉 Custom Greeting: Hey Nova, you're awesome! 🎉 🎉 Custom Greeting: Hey Elyndra, you're awesome! 🎉
Was ist passiert?
- Spring Boot findet
CustomGreetingService(wegen@Service) - Es prüft
@ConditionalOnMissingBeaninGreetingAutoConfiguration - Bedingung nicht erfüllt! Es gibt bereits einen
GreetingServiceBean! DefaultGreetingServicewird nicht erstelltCustomGreetingServicewird genutzt ✅
Das nennt man Überschreibbarkeit! Ein wichtiges Prinzip für flexible Starter.
💡 Pro-Tipp: Lösche die CustomGreetingService Klasse wieder für die nächsten Tests.
Bonus 2: Nested Properties – Komplexe Konfiguration
Für komplexere Konfigurationen kannst du Properties verschachteln!
GreetingProperties erweitern
Bearbeite GreetingProperties.java im Starter:
package com.javafleet.greeting;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "greeting")
public class GreetingProperties {
private String message = "Hello";
private boolean uppercase = false;
private String prefix = "";
/**
* Nested Properties für Format-Optionen
*/
private Format format = new Format();
// Getter/Setter für format
public Format getFormat() {
return format;
}
public void setFormat(Format format) {
this.format = format;
}
// Bestehende Getter/Setter...
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isUppercase() {
return uppercase;
}
public void setUppercase(boolean uppercase) {
this.uppercase = uppercase;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* Nested Class für Format-Konfiguration
*/
public static class Format {
private String emoji = "";
private String separator = ", ";
public String getEmoji() {
return emoji;
}
public void setEmoji(String emoji) {
this.emoji = emoji;
}
public String getSeparator() {
return separator;
}
public void setSeparator(String separator) {
this.separator = separator;
}
}
}
DefaultGreetingService anpassen
Bearbeite DefaultGreetingService.java:
@Override
public String greet(String name) {
String message = properties.getMessage();
// Prefix hinzufügen
if (properties.getPrefix() != null && !properties.getPrefix().isEmpty()) {
message = properties.getPrefix() + " " + message;
}
// Separator aus Format nutzen
String separator = properties.getFormat().getSeparator();
String greeting = message + separator + name + "!";
// Uppercase
if (properties.isUppercase()) {
greeting = greeting.toUpperCase();
}
// Emoji hinzufügen
String emoji = properties.getFormat().getEmoji();
if (emoji != null && !emoji.isEmpty()) {
greeting = emoji + " " + greeting + " " + emoji;
}
return greeting;
}
Starter neu bauen & testen
# Im Starter-Projekt mvn clean install # Im Demo-Projekt cd ../greeting-demo
Bearbeite application.properties:
greeting.message=Hello greeting.uppercase=false greeting.prefix= greeting.format.emoji=👋 greeting.format.separator= ->
Starte:
mvn spring-boot:run
Ausgabe:
👋 Hello -> Franz! 👋 👋 Hello -> Nova! 👋 👋 Hello -> Elyndra! 👋
Brilliant! 🎯 Beliebig verschachtelte Properties!
IDE Auto-Complete zeigt jetzt auch:
greeting.
├── message
├── uppercase
├── prefix
├── enabled
└── format.
├── emoji
└── separator
Bonus 3: Advanced Conditionals
Du kannst mehrere Conditionals kombinieren für komplexe Szenarien!
Beispiel: Conditional on Multiple Classes
@AutoConfiguration
@ConditionalOnClass({GreetingService.class, SomeOtherClass.class})
public class GreetingAutoConfiguration {
// Lädt nur wenn BEIDE Klassen im Classpath sind
}
Beispiel: Conditional on Bean
@Bean
@ConditionalOnBean(DataSource.class)
public GreetingService databaseGreetingService(DataSource dataSource) {
// Lädt nur wenn ein DataSource Bean existiert
return new DatabaseGreetingService(dataSource);
}
Beispiel: Custom Condition
Du kannst sogar eigene Conditions schreiben:
public class OnLinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return System.getProperty("os.name").toLowerCase().contains("linux");
}
}
@Bean
@Conditional(OnLinuxCondition.class)
public GreetingService linuxGreetingService() {
return new LinuxGreetingService();
}
💡 Pro-Tipp: Für Production-Starter überlege dir gut welche Conditionals du brauchst. Halte es so einfach wie möglich!
✅ Checkpoint: Hast du Tag 1 geschafft?
Grundlagen (🟢):
- [ ] Du verstehst was
@SpringBootApplicationmacht - [ ] Du kannst
@ConfigurationPropertiesnutzen - [ ] Du kennst
@ConditionalOnProperty,@ConditionalOnClass,@ConditionalOnMissingBean - [ ] Du hast
AutoConfiguration.importserstellt und verstanden - [ ] Du hast einen funktionierenden Starter gebaut
Professionals (🟡):
- [ ] Deine IDE zeigt Auto-Complete für Properties
- [ ] Du kannst den Starter mit
enabled=falseausschalten - [ ] Du kannst Debug-Modus nutzen (
debug=true) - [ ] Du verstehst den Conditions Evaluation Report
Bonus (🔵):
- [ ] Du kannst den Default-Service überschreiben
- [ ] Du hast Nested Properties implementiert
- [ ] Du verstehst die Überschreibbarkeit durch
@ConditionalOnMissingBean
Alles ✅? Du bist bereit für Tag 2!
Nicht alles funktioniert?
- Schau nochmal in Schritt 8 (Testing)
- Lade das komplette Projekt unten herunter
- Prüfe ob
AutoConfiguration.importskorrekt ist - Nutze
debug=truefür Troubleshooting - Stelle sicher dass
mvn clean installerfolgreich war
🔥 Elyndras Real Talk:
Nach der Session kam das Team zusammen…
Nova: „Elyndra, das war… WOW! Ich dachte immer Spring Boot macht einfach Magie. Aber jetzt verstehe ich es! Es ist wie… ein super intelligentes System das entscheidet was geladen wird!“
Elyndra: „Genau, Nova! Und das Schöne ist: Du kannst jetzt eigene ‚Magie‘ bauen. Das ist wie beim Refactoring – wenn du verstehst wie etwas funktioniert, kannst du es verbessern oder erweitern.“
Franz-Martin: „Elyndra hat es perfekt erklärt. @ConditionalOnProperty ist übrigens mein Favorit – elegant und mächtig. Wir nutzen das in fast jedem unserer Enterprise-Starter.“
Nova: „Aber eine Frage: Warum matchIfMissing = true? Warum nicht einfach nur laden wenn es explizit aktiviert ist?“
Elyndra: „Gute Frage! Das folgt dem Spring Boot Prinzip: Convention over Configuration. Der Starter soll out-of-the-box funktionieren, ohne dass du etwas konfigurieren musst. Du kannst ihn aber jederzeit mit enabled=false ausschalten.“
Code Sentinel: „Wichtig aus Security-Perspektive: Überlegt gut was eure Starter standardmäßig tun. matchIfMissing = true bedeutet der Code läuft automatisch. Das kann bei Security-relevanten Features problematisch sein.“
Franz-Martin: „Absolut richtig, Code Sentinel. Bei unserem Audit-Logging-Starter haben wir deshalb matchIfMissing = false – Logging muss explizit aktiviert werden.“
Nova: „Oh! Also bei Security-Features lieber false als Default?“
Code Sentinel: „Genau. Principle of Least Privilege – nichts ist automatisch aktiv, was Sicherheitsrisiken bergen könnte.“
Elyndra: „Sehr guter Punkt! Das ist wie beim Legacy-Code: Verstehe erst die Implikationen, bevor du Defaults setzt. Bei unserem greeting-starter ist es unkritisch, aber bei Production-Startern müssen wir vorsichtig sein.“
Nova: „Ich liebe das! Jetzt kann ich eigene Starter bauen! Vielleicht einen todo-reminder-starter?“
Elyndra: lächelt „Das wäre ein perfektes Übungsprojekt! Fang klein an, genau wie wir heute.“
❓ FAQ (Häufige Fragen)
Q: Warum sehe ich kein Auto-Complete für meine Properties?
A: Stelle sicher dass:
spring-boot-configuration-processorin derpom.xmlist- Du Maven neu geladen hast (Reimport in IDE)
- Du die App mindestens einmal gebaut hast (
mvn clean install) - Die
spring-configuration-metadata.jsongeneriert wurde (intarget/classes/META-INF/)
Q: Meine Auto-Configuration lädt nicht – wie debugge ich das?
A: Setze debug=true in application.properties und schau in die Console. Der „Conditions Evaluation Report“ zeigt dir GENAU welche Conditionals nicht erfüllt sind.
Q: Kann ich mehrere Auto-Configurations in einem Starter haben?
A: Ja! Einfach mehrere Zeilen in AutoConfiguration.imports einfügen:
com.javafleet.greeting.GreetingAutoConfiguration com.javafleet.greeting.OtherAutoConfiguration
Q: Was ist der Unterschied zwischen @Configuration und @AutoConfiguration?
A: @AutoConfiguration ist neu in Spring Boot 3 und speziell für Auto-Configuration gedacht. Es hat bessere Ordering-Unterstützung und ist semantisch klarer.
Q: Wie kann ich die Reihenfolge von Auto-Configurations steuern?
A: Nutze @AutoConfigureBefore und @AutoConfigureAfter:
@AutoConfiguration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@AutoConfigureBefore(JpaAutoConfiguration.class)
public class GreetingAutoConfiguration {
// ...
}
Q: Muss ich meinen Starter auf Maven Central publishen?
A: Nein! Für internen Gebrauch reicht mvn install um ihn lokal verfügbar zu machen. Für Teams kannst du einen Nexus/Artifactory verwenden.
Q: Was passiert mit dem Starter im Production Build?
A: Der Starter wird wie jede andere Dependency in dein JAR/WAR gepackt. Die Auto-Configuration läuft beim Start und erstellt die Beans. Keine Extra-Schritte nötig!
Q: Was macht ihr eigentlich wenn im Team mal Spannungen entstehen? Wie geht ihr mit zwischenmenschlichen Problemen um? 🤔
A: Gute Frage… Manche Geschichten passen nicht in Tech-Blogs. Die gehören eher zu Herz Schmerz und private logs. Aber das ist ein anderes Kapitel. 📖
📅 Nächster Kurstag: Tag 2
Morgen im Kurs / Nächster Blogbeitrag:
„Tag 2: Spring Data JPA Basics – Von ArrayList zur Datenbank“
Was du lernen wirst:
- JPA Setup mit MariaDB
- Erste Entity mit
@Entity,@Id,@GeneratedValue - Repository Pattern mit
JpaRepository - Service-Layer Umstellung von ArrayList zu Database
- Transaction Management verstehen
Warum wichtig? Fast jede Enterprise-Anwendung braucht Datenpersistenz. Spring Data JPA macht aus mühsamer JDBC-Arbeit elegante Repository-Calls.
Voraussetzung: Tag 1 abgeschlossen
👉 Zum Blogbeitrag Tag 2 (erscheint morgen)
📚 Deine Fortschritts-Übersicht
| Tag | Thema | Status |
|---|---|---|
| ✅ 1 | Auto-Configuration & Custom Starter | ABGESCHLOSSEN! 🎉 |
| → 2 | Spring Data JPA Basics | Als nächstes |
| 3 | JPA Relationships & Queries | Noch offen |
| 4 | Spring Security – Part 1 | Noch offen |
| 5 | Spring Security – Part 2 | Noch offen |
| 6 | Caching & Serialisierung | Noch offen |
| 7 | Messaging & Email | Noch offen |
| 8 | Testing & Dokumentation | Noch offen |
| 9 | Spring Boot Actuator | Noch offen |
| 10 | Template Engines & Microservices | Noch offen |
Du hast 10% des Kurses geschafft! 💪
Alle Blogbeiträge dieser Serie:
👉 Spring Boot Aufbau-Kurs – Komplette Übersicht
📥 Download & Ressourcen
Projekt zum Download:
👉 Github: greeting-spring-boot-starter
Was ist im Repository enthalten:
- ✅ Kompletter Starter Code (Spring Boot 3)
- ✅ Demo-Projekt zum Testen
- ✅
application.propertiesBeispiele - ✅ Ausführliche README mit Schnellstart
- ✅ Alle Bonus-Features
Projekt starten:
# Repository klonen git clone https://github.com/javafleet/Tag1-Spring-Boot-Aufbau-Custom-Starter.git cd Tag1-Spring-Boot-Aufbau-Custom-Starter # 1. Starter bauen & installieren cd greeting-spring-boot-starter mvn clean install # 2. Demo-App starten cd ../greeting-demo mvn spring-boot:run # 3. Im Browser testen # http://localhost:8080 sollte jetzt laufen
Probleme? Erstelle ein Issue auf Github oder kontaktiere uns!
Das war Tag 1 vom Spring Boot Aufbau-Kurs!
Du kannst jetzt:
- ✅ Spring Boot Auto-Configuration verstehen
- ✅ Eigene Starter mit
@ConfigurationPropertiesentwickeln - ✅
@ConditionalAnnotations richtig einsetzen - ✅
AutoConfiguration.importsnutzen (Spring Boot 3!) - ✅ Die Spring Boot „Magie“ erklären
- ✅ Properties mit IDE Auto-Complete konfigurieren
Morgen tauchen wir in Spring Data JPA ein – von ArrayList zur echten Datenbank! 🚀
Keep coding, keep learning! 💙
Tag 2 erscheint morgen im Kurs. Bis dahin: Happy Coding!
Tags: #SpringBoot #CustomStarter #AutoConfiguration #ConfigurationProperties #Java #Tutorial #Tag1

