20 Der ApplicationContext

Der ApplicationContext ist das Gehirn einer Spring-Anwendung. Er kennt alle Beans, verwaltet ihre Lebenszyklen und vermittelt zwischen ihnen. Wenn du Spring verstehen willst, musst du den ApplicationContext verstehen.

20.1 Was ist der ApplicationContext?

Technisch ist der ApplicationContext ein Interface. Praktisch ist er der Container, der alles zusammenhält.

Die Bean Registry speichert alle Bean-Definitionen. Die Bean Factory erzeugt Beans bei Bedarf. Das Event System ermöglicht Kommunikation zwischen Komponenten. Der Resource Loader findet Dateien und Konfigurationen. Das Environment kennt Properties und Profile.

20.2 Der Context in Aktion

Im Arcade-Projekt existiert genau ein ApplicationContext. Er wird beim Start erzeugt:

@SpringBootApplication
public class ArcadeHighscoreApplication {
    public static void main(String[] args) {
        // run() erzeugt und konfiguriert den ApplicationContext
        ApplicationContext context = SpringApplication.run(
            ArcadeHighscoreApplication.class, args);
    }
}

Nach dem Start kannst du den Context befragen:

// Alle Bean-Namen ausgeben
String[] beanNames = context.getBeanDefinitionNames();
for (String name : beanNames) {
    System.out.println(name);
}

// Eine bestimmte Bean holen
GameService gameService = context.getBean(GameService.class);

In der Praxis brauchst du das selten. Spring injiziert Beans automatisch. Aber zu wissen, dass der Context existiert, hilft beim Verständnis.

20.3 Singleton-Container

Der ApplicationContext garantiert: Jede Bean existiert genau einmal. Egal wie oft du getBean() aufrufst oder wie oft eine Bean injiziert wird – es ist immer dieselbe Instanz.

Drei Konsumenten, eine Instanz. Das spart Speicher und stellt sicher, dass alle denselben Zustand sehen.

20.4 Context-Hierarchien

In komplexen Anwendungen kann es mehrere Contexts geben. Ein Parent-Context enthält gemeinsame Beans, Child-Contexts enthalten spezifische.

Für das Arcade-Projekt und die meisten Spring-Boot-Anwendungen ist das irrelevant. Ein Context reicht. Aber das Konzept erklärt, warum manche Dokumentation von “Contexts” im Plural spricht.

20.5 Der Context als Vermittler

Beans kommunizieren nicht direkt miteinander. Sie kommunizieren über den Context.

Wenn der HomeController den GameService aufruft, weiß er nicht, wo der Service herkommt. Er hat eine Referenz, die der Context bereitgestellt hat. Diese Indirektion ermöglicht:

Der Context ist der unsichtbare Mittelsmann, der alles orchestriert.

20.6 ApplicationContext vs. BeanFactory

In älteren Tutorials taucht manchmal BeanFactory auf. Das ist der Vorfahre des ApplicationContext – schlanker, aber mit weniger Features.

Feature BeanFactory ApplicationContext
Bean-Erzeugung Ja Ja
Dependency Injection Ja Ja
Lifecycle Callbacks Eingeschränkt Vollständig
Event System Nein Ja
Internationalisierung Nein Ja
Resource Loading Nein Ja

ApplicationContext ist die moderne Wahl. BeanFactory ist Legacy. In Spring Boot arbeitest du immer mit ApplicationContext.

20.7 Zugriff auf den Context

Manchmal brauchst du direkten Zugriff auf den Context. Spring bietet dafür ApplicationContextAware:

@Service
public class DynamicServiceLoader implements ApplicationContextAware {
    
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext context) {
        this.context = context;
    }
    
    public <T> T getService(Class<T> serviceType) {
        return context.getBean(serviceType);
    }
}

Oder eleganter per Injection:

@Service
public class DynamicServiceLoader {
    
    private final ApplicationContext context;
    
    public DynamicServiceLoader(ApplicationContext context) {
        this.context = context;
    }
}

Der ApplicationContext ist selbst eine Bean. Du kannst ihn injizieren wie jede andere Abhängigkeit.

Aber Vorsicht: Direkter Context-Zugriff ist oft ein Zeichen für Design-Probleme. Wenn du getBean() rufst, umgehst du die Dependency Injection. Tu das nur, wenn es wirklich nötig ist – etwa für dynamisches Laden von Plugins.