11 Dependency Injection als Entkopplung

Inversion of Control ist das Prinzip. Dependency Injection ist die Technik, mit der Spring dieses Prinzip umsetzt. Der Name beschreibt genau, was passiert: Abhängigkeiten (Dependencies) werden eingespritzt (injected).

11.1 Was ist eine Dependency?

Eine Dependency ist jedes Objekt, das eine Klasse braucht, um ihre Arbeit zu erledigen. Im Arcade-Projekt hat ein hypothetischer LeaderboardService mehrere Dependencies:

Ohne ScoreRepository kann der Service keine Scores laden. Ohne PlayerRepository keine Spielernamen. Ohne CacheService keine Performance-Optimierung. Diese Objekte sind Abhängigkeiten – der Service hängt von ihnen ab.

11.2 Injection statt Konstruktion

Dependency Injection bedeutet: Die Abhängigkeiten werden von außen bereitgestellt, nicht intern erzeugt.

// OHNE Dependency Injection
public class LeaderboardService {
    private ScoreRepository scores = new MongoScoreRepository();
    private PlayerRepository players = new MongoPlayerRepository();
}

// MIT Dependency Injection
public class LeaderboardService {
    private final ScoreRepository scores;
    private final PlayerRepository players;
    
    public LeaderboardService(ScoreRepository scores, PlayerRepository players) {
        this.scores = scores;
        this.players = players;
    }
}

Im ersten Fall ist die Klasse für die Erzeugung verantwortlich. Im zweiten Fall erwartet sie, dass jemand anders die Objekte liefert. Dieser “jemand anders” ist Spring.

11.3 Entkopplung durch Interfaces

Die wahre Macht von DI entfaltet sich durch Interfaces. Statt konkreter Klassen verwendet der Service abstrakte Typen:

Der LeaderboardService weiß nicht, ob er mit MongoDB oder PostgreSQL arbeitet. Er kennt nur das Interface. Die konkrete Implementierung wird zur Laufzeit injiziert – und kann jederzeit ausgetauscht werden.

11.4 Das Arcade-Beispiel

Im Arcade-Projekt könnte ein HighscoreService so aussehen:

@Service
public class HighscoreService {
    
    private final ScoreRepository scoreRepository;
    private final GameRepository gameRepository;
    
    public HighscoreService(ScoreRepository scoreRepository, 
                           GameRepository gameRepository) {
        this.scoreRepository = scoreRepository;
        this.gameRepository = gameRepository;
    }
    
    public List<Score> getTopScores(String gameId, int limit) {
        Game game = gameRepository.findById(gameId)
            .orElseThrow(() -> new GameNotFoundException(gameId));
            
        return scoreRepository.findByGameOrderByPointsDesc(game, limit);
    }
}

Die @Service-Annotation sagt Spring: “Das ist eine Komponente, verwalte sie.” Die Constructor-Parameter sagen Spring: “Diese Objekte brauche ich.”

Spring sieht das und handelt:

  1. Es findet eine Bean vom Typ ScoreRepository
  2. Es findet eine Bean vom Typ GameRepository
  3. Es erzeugt den HighscoreService mit diesen Beans

Du schreibst keinen Verdrahtungs-Code. Spring erledigt das.

11.5 Lose vs. enge Kopplung

Kopplung beschreibt, wie stark zwei Komponenten voneinander abhängen. Enge Kopplung bedeutet: Eine Änderung hier erfordert Änderungen dort. Lose Kopplung bedeutet: Komponenten können unabhängig voneinander geändert werden.

Aspekt Enge Kopplung Lose Kopplung (DI)
Abhängigkeit Konkrete Klasse Interface
Erzeugung new im Code Container injiziert
Änderbarkeit Quellcode anpassen Konfiguration anpassen
Testbarkeit Echte Objekte nötig Mocks möglich

Dependency Injection erzwingt lose Kopplung. Du kannst gar nicht anders, als gegen Interfaces zu programmieren – denn du kontrollierst nicht, welche Implementierung du bekommst.

11.6 Der Dominoeffekt

Ohne DI führt eine Änderung oft zu Kettenreaktionen:

Mit DI bleibt die Änderung isoliert:

Der Service arbeitet weiter mit dem gleichen Interface. Dass dahinter jetzt PostgreSQL statt MongoDB steckt, merkt er nicht.

11.7 Zusammenspiel der Konzepte

IoC und DI gehören zusammen, sind aber nicht dasselbe:

IoC ist die Philosophie: Kontrolle abgeben. DI ist die Methode: Abhängigkeiten von außen liefern. Spring ist das Werkzeug: Der Container, der alles zusammenbringt.