CodeGym /Kurse /Spring Core /Gemischte Konfiguration ohne Chaos

Gemischte Konfiguration ohne Chaos

Spring Core
Level 23, Lektion 3
Verfügbar

1. Gemischte Konfiguration als Normalität

Wenn XML nicht mehr wie eine separate Technologie erscheint, entsteht die bodenständigere Frage: Wie lebt man damit innerhalb einer normalen Anwendung, die bereits eine Java-Konfiguration besitzt? Wenn wir „gemischte Konfiguration“ hören, malt das Gehirn eines Anfängers normalerweise Chaos: die Hälfte des Projekts in XML, die Hälfte in Annotationen, und irgendwo zwischen ihnen versteckt sich ein Bug, der immer nur dienstags auftaucht. In der Praxis ist alles viel gelassener, wenn man im Voraus einen einfachen Gedanken akzeptiert: Migration ist ein Prozess, kein Ereignis. Und im Prozess müssen Sie zwei Syntaxen in einer Anwendung handhaben können, sodass der Container vorhersagbar bleibt.

Stellen Sie sich ein typisches Szenario vor. Sie haben ein Projekt, das bereits auf @Configuration + @ComponentScan umgestellt wurde, aber es gibt noch ein kleines Legacy-Modul (z.B. Benachrichtigungen), das anzufassen riskant ist: „es funktioniert – nicht anfassen“. Gleichzeitig müssen Sie das Projekt weiterentwickeln: neue Beans hinzufügen, Wiring ändern, neue Implementierungen von Interfaces anbinden. Eine vollständige „Big-Bang“-Migration aller XML in Java-Konfiguration ist oft zu riskant und teuer – besonders wenn Sie nicht sicher sind, dass Sie jede Zeile der Legacy-Datei verstehen.

Gemischte Konfiguration ist genau dieser ingenieurtechnische Kompromiss: Wir binden XML in den modernen Kontext ein, machen das Projekt lauffähig und übertragen dann Stück für Stück, bis nur noch Java-Konfiguration übrig ist. Hauptsache, das geschieht kontrolliert und nicht nach dem Motto „na gut, importieren wir alles und schauen, was explodiert“.

2. Legacy XML: separater Kontext oder gemeinsamer Container

Wenn Sie eine XML-Datei haben, ist der einfachste „technische“ Weg, sie als separaten ClassPathXmlApplicationContext zu starten und ein paar Beans daraus zu holen. Das funktioniert tatsächlich und ist manchmal für Experimente nützlich. Aber wenn Ihr Ziel eine echte Anwendung (unser ContextFlow) ist, dann möchte man fast immer, dass Java-Konfiguration und XML in einem ApplicationContext leben – sonst beginnt die lustige Quest „Wie übergebe ich einen Bean aus einem Container in den anderen“.

Vergleichen wir zwei Ansätze in einer Tabelle, ohne Glaubenskriege und ohne „XML ist böse, Java ist gut“ (beide Syntaxen können BeanDefinition gleichermaßen gut beschreiben):

Ansatz Wie sieht es aus Vorteile Nachteile
Separater XML-Kontext new ClassPathXmlApplicationContext("...xml") Schnelle Überprüfung eines Legacy-Fragments, isoliertes Experimentieren Beans leben nicht im selben Container, Wiring zwischen den Welten wird umständlich
Gemeinsamer Kontext durch Import @ImportResource("classpath:...xml") innerhalb der Java-Konfiguration Ein Container, einheitliche Auflösung von Abhängigkeiten, einfachere schrittweise Migration Man muss auf Namenskonflikte und doppelte Definitionen achten

In ContextFlow benötigen wir genau die zweite Variante: ein Container, ein Abhängigkeitsgraph, ein Profil-/ Ressourcen-/ Event-Listener-Set – und eine kleine Legacy-Insel, die wir nach und nach „zivilisieren“.

Hier ist ein Diagramm, wie es gedanklich aussieht (ja, es ist dasselbe Bean-Modell, nur mit mehr Definitionsquellen):

flowchart TD
  Java["@Configuration / @Bean / scanning"] --> BD[BeanDefinitions registry]
  XML["legacy *.xml"] --> BD
  BD --> Beans["Erstellte Bean-Instanzen"]
  Beans --> App["ContextFlow: Szenarien, Services, Listener"]

Der entscheidende Punkt: @ImportResource erzeugt keinen „zweiten Container“. Es fügt einfach eine weitere Quelle von BeanDefinition im aktuellen Container hinzu.

3. @ImportResource: Was ist das und was tut es wirklich

@ImportResource ist eine Annotation aus der Welt der Java-Konfiguration, die Spring mitteilt: „Hier ist eine XML-Ressource, lies daraus Bean-Definitionen und füge sie demselben Kontext hinzu.“ Keine separate Magie: Der Container baut immer noch ein einheitliches Bean-Registry auf, erzeugt dann Objekte, injiziert Abhängigkeiten und wendet den Lifecycle an.

Minimalbeispiel einer Bridge-Konfiguration (in der Regel in einem Paket config.legacybridge):

package com.example.contextflow.config.legacybridge;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
// Binden legacy XML in DEN GLEICHEN ApplicationContext ein (erstellen keinen separaten Container)
@ImportResource("classpath:/legacy/legacy-notification-context.xml")
public class LegacyBridgeConfig {
    // Klasse ist leer – sie dient als „Anker“ für den Import der XML-Ressource
}

Beachten Sie classpath:/.... Das ist aus zwei Gründen wichtig. Erstens liegt die XML in src/main/resources, also ist sie zur Laufzeit im Classpath verfügbar (auch innerhalb eines Jars). Zweitens haben wir bereits die Resource-Abstraktion gelernt: „classpath“ ist keine „Datei auf der Festplatte“, sondern eine Ressource der Anwendung.

Selbst wenn diese XML später um ein paar weitere Beans wächst, ändert sich der Einstiegspunkt nicht: Die Bridge-Konfiguration mischt ihre Definitionen weiterhin einfach in den gemeinsamen Container.

Danach bauen wir den Hauptkontext wie gewohnt auf und fügen einfach LegacyBridgeConfig zur Liste der Konfigurationen hinzu:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

// Wichtig: ein AnnotationConfigApplicationContext, in dem sowohl @Bean als auch XML-Bean-Definitionen vorhanden sein werden
try (var ctx = new AnnotationConfigApplicationContext(
        com.example.contextflow.config.core.CoreConfig.class,
        com.example.contextflow.config.legacybridge.LegacyBridgeConfig.class
)) {
    // Überprüfen, dass der Bean aus der XML tatsächlich im gemeinsamen Kontext registriert ist
    System.out.println(ctx.containsBean("legacyNotificationSender")); // true
}

Wenn Sie true sehen, bedeutet das, dass legacyNotificationSender als Bean-Definition registriert und im Kontext verfügbar ist. Wichtig: Wir haben nicht über einen separaten ClassPathXmlApplicationContext darauf zugegriffen. Wir haben keinen zweiten Container erstellt. Wir haben lediglich XML-Definitionen in den gemeinsamen Container aufgenommen.

Ein weiterer praktischer Punkt: @ImportResource akzeptiert ein String-Array, sodass Sie mehrere kleine XML-Fragmente einbinden können (aber wirklich kleine, sonst erhalten Sie wieder einen „riesigen XML-Monolithen“, nur jetzt importiert):

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource({
        // Man kann mehrere XML-Fragmente importieren, wenn Sie Legacy nach Modulen organisieren
        "classpath:/legacy/legacy-notification-context.xml",
        "classpath:/legacy/legacy-audit-context.xml"
})
class LegacyBridgeConfig {
}

In unserem Kurs halten wir ein einziges Legacy-Fragment, daher ist dies eher eine Veranschaulichung als eine Empfehlung „binden Sie alle Ihre 30 XML-Dateien ein“.

4. Wiring zwischen Java-Konfiguration und XML: Abhängigkeiten in beide Richtungen

Das Nützlichste an @ImportResource ist, dass Beans aus XML und Beans aus Java-Konfiguration wie Nachbarn im selben Treppenhaus leben: Sie wissen voneinander, können aufeinander verweisen und sich sogar um einen Platz unter der Sonne streiten. Das ist praktisch, aber genau hier darf man den Kopf nicht verlieren: Ein Container bedeutet auch einen einheitlichen Mechanismus zur Kandidatenauflösung.

An einem Fragment wird das am besten sichtbar. In der XML lebt legacyNotificationSender und nutzt bereits den Infrastruktur-Bean messageSource aus dem gemeinsamen Kontext:

<bean id="legacyNotificationSender"
      class="com.example.contextflow.infrastructure.notification.legacy.LegacyConsoleNotificationSender"
      init-method="init" destroy-method="destroy">
    <property name="appName" value="ContextFlow (legacy)"/>
    <property name="messageSource" ref="messageSource"/>
</bean>

Und in der Java-Konfiguration erstellen wir einen Service, der genau diese Legacy-Implementierung nutzen möchte:

import com.example.contextflow.application.service.NotificationDispatchService;
import com.example.contextflow.domain.ports.NotificationSender;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class NotificationModuleConfig {

    @Bean
    NotificationDispatchService notificationDispatchService(
            // Nehmen genau den legacy-Bean aus der XML anhand seiner id
            @Qualifier("legacyNotificationSender") NotificationSender sender
    ) {
        return new NotificationDispatchService(sender);
    }
}

Hier sieht man in einem Bild beide Seiten der Verbindung. Der XML-Bean erhält messageSource aus dem gemeinsamen Kontext über ref="messageSource". Die Java-Konfiguration wählt ihrerseits legacyNotificationSender per Qualifier aus und baut darauf einen Service auf. Ein Container, eine Candidate-Resolution, ein Lifecycle.

Wenn NotificationSender der einzige Kandidat wäre, wäre der Qualifier vielleicht nicht nötig. Aber in ContextFlow gibt es mehrere Implementierungen, daher ist der explizite Name hier beruhigender: Man sieht sofort, dass der Service auf dem Legacy-Zweig sitzt.

5. Schrittweise Migration XML → Java-Konfiguration

Der häufigste Anfängerfehler ist der Versuch, „das XML einfach an einem Abend in Java umzuschreiben“. Das ist ungefähr so wie „das gesamte Projekt am Wochenende auf Microservices umstellen“: Theoretisch möglich, aber meistens hat man dann zwei Projekte – das alte und das „fast neue“ – und keins läuft. Eine schrittweise Migration ist nötig, damit die Anwendung zu jedem Zeitpunkt in einem funktionsfähigen Zustand bleibt.

Nachfolgend eine Strategie, die Sie sich gut als Plan merken und laut aussprechen können, wenn Sie auf Legacy-XML schauen und das leichte Verlangen verspüren, in einen Wald ohne Internet zu fliehen.

Schritt A. Legacy-Fragment isolieren und über @ImportResource einbinden

Der erste Schritt ist überhaupt zu erkennen, dass es sich um Legacy handelt. In ContextFlow halten wir solche Dateien in src/main/resources/legacy/ und binden sie über eine separate Konfiguration wie z.B. LegacyBridgeConfig ein. Das schafft eine visuelle Grenze: „hier ist Legacy“. Psychologisch erleichtert das bereits das Leben, weil XML nicht mehr wie Konfetti im Projekt verstreut ist.

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource("classpath:/legacy/legacy-notification-context.xml")
class LegacyBridgeConfig {
}

Wichtig: In diesem Schritt migrieren wir nichts. Wir machen das Projekt lediglich lauffähig und kontrollierbar.

Schritt B. Eine „Karte“ der XML erstellen: id → class → Abhängigkeiten → Lifecycle

Jetzt brauchen wir ein kleines Inventar-Ritual. Nicht schlimm, einfach technisch. Wir notieren jedes <bean> und halten fest, was es tut. Das kann man sogar als Tabelle in Notizen oder direkt als Kommentar festhalten.

Beispiel einer Karte für das Notification-Fragment, in dem bereits ein Sender und ein darauf aufbauender Service existieren:

Bean-ID Klasse Injektion Abhängig von Lifecycle
legacyNotificationSender LegacyConsole NotificationSender Property messageSource (ref), appName (value) init, destroy
legacyNotification DispatchService NotificationDispatchService Konstruktor legacyNotificationSender (ref) —

Wenn Sie eine solche Karte haben, hören Sie auf, „zu raten, was sich der XML-Autor gedacht hat“, und beginnen, das tatsächliche Containermodell zu sehen.

Schritt C. Einen Bean zur Migration auswählen und in die Java-Konfiguration übertragen

Ein guter erster Kandidat ist ein lokaler Bean, der nicht gleich ein halbes Projekt mit sich zieht. In unserem Fall ist das legacyNotificationSender: Er hat bereits Eigenschaften, einen Verweis auf einen anderen Bean und einen Lifecycle, aber der Graph um ihn herum ist noch klein und überschaubar.

XML:

<bean id="legacyNotificationSender"
      class="com.example.contextflow.infrastructure.notification.legacy.LegacyConsoleNotificationSender"
      init-method="init" destroy-method="destroy">
    <property name="appName" value="ContextFlow (legacy)"/>
    <property name="messageSource" ref="messageSource"/>
</bean>

Java-Äquivalent:

import com.example.contextflow.infrastructure.notification.legacy.LegacyConsoleNotificationSender;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class NotificationConfig {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    LegacyConsoleNotificationSender legacyNotificationSender(MessageSource messageSource) {
        var sender = new LegacyConsoleNotificationSender();
        sender.setAppName("ContextFlow (legacy)");
        sender.setMessageSource(messageSource);
        return sender;
    }
}

Wir haben bewusst den Namen legacyNotificationSender beibehalten: Genau diesen Namen kennen bereits die XML-ref, der @Qualifier und der Diagnosecode.

Schritt D. Die alte Deklaration aus der XML entfernen/deaktivieren und die Anwendung erneut starten

Das ist ein kritischer Disziplin-Moment. Solange der Bean sowohl in XML als auch in der Java-Konfiguration deklariert ist, wird der Container entweder die Definition überschreiben (wenn Overriding erlaubt ist) oder abbrechen (wenn verboten). In beiden Fällen riskieren Sie einen stillen Fehler: „Es scheint, als hätten wir migriert, aber in Wirklichkeit läuft die alte Version“.

Daher die Regel: Bean übertragen – aus XML entfernen. In kleinen Schritten, aber ehrlich.

Schritt E. Für den nächsten Bean wiederholen

Ein sehr wichtiger psychologischer Punkt. Migration ist kein Architektur-Refactoring. Während der Übertragung werden Sie versucht sein: „Lass uns gleich noch Setter-Injektion durch Konstruktor-Injektion ersetzen“, „lass uns gleich das Interface umbauen“, „lass uns gleich die Hälfte der Beans wegwerfen“. Tun Sie es nicht. Das kommt später. Das Ziel jetzt ist, das Verhalten zu erhalten, aber die Konfigurationssyntax zu ändern.

Wenn die XML Setter-Injektion verwendet hat, migrieren Sie sie als Setter-Injektion in der @Bean-Methode, selbst wenn Sie Konstruktoren sehr mögen. Wir mögen Konstruktoren, aber die Produktionsmigration liebt Stabilität.

6. Übertragung von Abhängigkeiten und Lifecycle

Wenn die Migration zu komplexeren Beans fortschreitet, ist es wichtig zu lernen, wie man XML-Formen des Wires in Java-Formen übersetzt, ohne das Verhalten zu verlieren. Die gute Nachricht: Sie kennen bereits alle Ideen (Konstruktor, Eigenschaften, Lifecycle). Die schlechte Nachricht: In Legacy-Dateien kann alles durcheinander sein.

Migration von constructor-arg ref="..." in die Java-Konfiguration

XML:

<bean id="auditService" class="com.example.contextflow.application.service.AuditService">
    <constructor-arg ref="auditWriter"/>
</bean>

Java-Konfiguration (das direkteste Äquivalent ist der Parameter der @Bean-Methode):

import com.example.contextflow.application.service.AuditService;
import com.example.contextflow.domain.ports.AuditWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class AuditConfig {

    @Bean
    AuditService auditService(AuditWriter auditWriter) {
        return new AuditService(auditWriter);
    }
}

Spring setzt automatisch AuditWriter aus dem Kontext ein. Wenn es mehrere Kandidaten gibt, verwenden Sie @Qualifier, wie Sie es bereits gelernt haben.

Migration von <property name="..."> in die Java-Konfiguration

XML:

<bean id="reportOutputManager"
      class="com.example.contextflow.support.lifecycle.ReportOutputManager">
    <property name="outputDir" value="build/reports"/>
</bean>

Java-Konfiguration (wir erstellen das Objekt und rufen den Setter auf):

import com.example.contextflow.support.lifecycle.ReportOutputManager;
import java.nio.file.Path;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class ReportingConfig {

    @Bean
    ReportOutputManager reportOutputManager() {
        var m = new ReportOutputManager();
        m.setOutputDir(Path.of("build/reports"));
        return m;
    }
}

Ja, das sieht „nicht so schön“ aus wie ein Konstruktor. Aber es ist eine ehrliche Migration: In XML gab es Property-Injektion – in der Java-Konfiguration gibt es sie auch. Und hier ist es wichtig, einen weiteren Punkt nicht zu übersehen: In der XML hat der Container den String value="build/reports" zusätzlich in den erforderlichen Typ konvertiert. In der Java-Konfiguration wird der Zieltyp normalerweise explizit erstellt, daher taucht hier Path.of(...) auf.

Migration von init-method / destroy-method in die Java-Konfiguration

XML:

<bean id="templateCatalog"
      class="com.example.contextflow.infrastructure.resources.NotificationTemplateCatalog"
      init-method="loadTemplates"
      destroy-method="clearCache"/>

Java-Konfiguration:

import com.example.contextflow.infrastructure.resources.NotificationTemplateCatalog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class TemplatesConfig {

    // Direkte Übertragung von init-method/destroy-method aus XML in @Bean-Metadaten
    @Bean(initMethod = "loadTemplates", destroyMethod = "clearCache")
    NotificationTemplateCatalog templateCatalog() {
        return new NotificationTemplateCatalog();
    }
}

Das ist die direkte Übersetzung der Lifecycle-Einstellung in eine andere Syntax. Und es passt gut zu dem, was wir am Tag über den Lifecycle gelernt haben: @Bean(initMethod=...) ist ein normales Werkzeug, besonders bei der Migration, wenn Sie nicht in den Code der Klasse eingreifen und @PostConstruct hinzufügen möchten.

7. Grenzen kontrollieren: Namenskonflikte, Duplikate und Scannen aus XML

Gemischte Konfiguration geht normalerweise nicht kaputt, weil @ImportResource „böse“ ist, sondern weil wir aufhören, die Grenzen zu kontrollieren. In Legacy-XML trifft man leicht auf context:component-scan, context:annotation-config, Property-Placeholder-Infrastruktur und sogar einige unerwartete Aliase. Und wenn Sie das „wie es ist“ importieren, können Sie versehentlich Überflüssiges aktivieren und die Hälfte der Anwendung doppelt zusammensetzen.

Die erste Risikozone – Bean-Namenskonflikte. XML liebt explizite id="...", Java-Konfiguration liebt Methodennamen von @Bean. Scannen benennt Beans gerne nach den Regeln des lowerCamelCase aus dem Klassennamen. All das trifft in einem Container aufeinander, daher sind Namenskonflikte absolut real. Die sicherste Gewohnheit bei der Migration ist, Namen bei der Übertragung beizubehalten und alte Deklarationen sofort zu entfernen, nicht „irgendwann später“.

Die zweite Risikozone – doppeltes Scannen. Zum Beispiel haben Sie in der Java-Konfiguration bereits ein @ComponentScan("com.example.contextflow"), und die Legacy-XML enthält plötzlich context:component-scan base-package="com.example.contextflow.infrastructure.notification". Ergebnis: Der Container versucht zweimal, dieselben Komponenten zu registrieren. Manchmal bemerken Sie das sofort (durch einen Namenskonflikt), manchmal nicht (wenn die Namen unterschiedlich sind), und dann haben Sie eine Situation: „Warum habe ich zwei NotificationSender, obwohl ich nur einen hinzugefügt habe?“

Die dritte Risikozone – Annotationsinfrastruktur und Platzhalter. Wenn die XML ${...}-Platzhalter verwendet, erwartet sie, dass im Kontext eine Infrastruktur vorhanden ist, die sie auflösen kann. In unserem Projekt haben wir bereits die Environment und die Platzhalterunterstützung in der Java-Konfiguration hochgezogen, daher wird normalerweise alles gut gehen. Aber wenn Sie ein XML-Fragment in einen „nackten“ Kontext ohne diese Dinge importieren, kann es beim Start scheitern – nicht weil die XML schlecht ist, sondern weil ihr die Infrastruktur-Beans fehlen.

Und schließlich die nützlichste Disziplin: Halten Sie das Legacy-Modul klein und isoliert. Im Idealfall sollte die Legacy-XML nur konkrete Beans beschreiben und nicht „die Hälfte der Anwendung aufbauen“. Dann haben Sie die Chance, sie in wenigen Schritten ohne nervöses Zucken zu migrieren.

Minimalbeispiel für ContextFlow: Legacy als Modul einbinden

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ContextFlowApp {
    public static void main(String[] args) {
        // Einheitlichen Kontext hochziehen: CoreConfig + Brücke zur Legacy-XML
        try (var ctx = new AnnotationConfigApplicationContext(
                com.example.contextflow.config.core.CoreConfig.class,
                com.example.contextflow.config.legacybridge.LegacyBridgeConfig.class
        )) {
            // Schnelle Sanity-Check-Prüfung: Bean aus XML ist tatsächlich im Container
            System.out.println(ctx.containsBean("legacyNotificationSender")); // true
        }
    }
}

Wenn true erscheint, ist der Legacy-Bean tatsächlich ein Teil des Containers. Danach können Sie ihn Schritt für Schritt migrieren, ohne die Anwendung vollständig neu zu bauen und ohne eine separate Welt für die XML zu schaffen.

8. Typische Fehler bei gemischter Konfiguration

Fehler Nr. 1: XML importieren, ohne seine Grenzen zu verstehen.
Wenn Sie eine Legacy-Datei in der Hoffnung einbinden, „der Container wird das schon irgendwie regeln“, nehmen Sie sich selbst den größten Vorteil von Spring – die Vorhersagbarkeit. Der richtige Ansatz beginnt mit der Beantwortung der Frage: Wofür ist dieses XML-Fragment zuständig und welche Beans soll es dem Container liefern? Ohne das schleppt man leicht zusätzliches Scannen, zusätzliche Platzhalter und die Hälfte der Infrastruktur „als Zugabe“ mit.

Fehler Nr. 2: Denselben Bean sowohl in XML als auch in Java-Konfiguration behalten.
Das ist ein Klassiker der Migration. Sie haben <bean id="legacyNotificationSender" .../> in @Bean legacyNotificationSender() übertragen, aber vergessen, die alte Deklaration aus der XML zu entfernen. Im besten Fall bricht der Container ab und sagt ehrlich, dass es einen Konflikt gibt. Im schlimmsten Fall überschreibt eine Definition die andere, und Sie haben die Situation: „Ich habe angeblich eine neue Konfiguration, aber irgendwie läuft noch die alte.“ Die Disziplin ist einfach: Übertragen – entfernen.

Fehler Nr. 3: Den Bean-Namen „ein bisschen ändern, damit er schöner klingt“.
Es scheint harmlos, legacyNotificationSender in consoleNotificationSenderLegacy umzubenennen – bis Sie sich daran erinnern, dass irgendwo in der XML ein ref="legacyNotificationSender" steht und irgendwo im Java-Code ein @Qualifier("legacyNotificationSender"). Bei der Migration ist es besser, die Namen so zu lassen, wie sie sind, und die Schönheitskorrektur erst vorzunehmen, wenn alles übertragen und stabilisiert ist.

Fehler Nr. 4: Gleichzeitig migrieren und das Design refaktorieren.
Man möchte unbedingt zusammen mit der Übertragung aus XML die Setter-Injektion durch Konstruktor-Injektion ersetzen, das Interface umschreiben, ein paar Klassen wegwerfen und „endlich richtig machen“. Aber dann hören Sie auf zu verstehen, was genau kaputtgegangen ist: die Migration oder das Refactoring. Erreichen Sie zuerst äquivalentes Verhalten in der Java-Konfiguration, und verbessern Sie dann in einem separaten Schritt das Design.

Fehler Nr. 5: Vergessen, dass die importierte XML neue Kandidaten hinzufügen und das Autowiring zerstören kann.
In ContextFlow gibt es bereits Stellen mit mehreren Implementierungen von Interfaces. Der Import einer XML kann unbemerkt eine weitere Implementierung hinzufügen, und Ihre Konstruktor-Injektion beginnt mit NoUniqueBeanDefinitionException zu scheitern. Das ist kein Grund, „XML zu hassen“, sondern ein Grund, sich an die Werkzeuge zu erinnern: @Qualifier, @Primary, explizite Bean-Namen und saubere Scannen-Grenzen.

1
Aufgabe
Spring Core, Level 23, Lektion 3
Gesperrt
XML-Einbindung in Java-Konfiguration mit `@ImportResource`
XML-Einbindung in Java-Konfiguration mit `@ImportResource`
1
Aufgabe
Spring Core, Level 23, Lektion 3
Gesperrt
Teilweise Migration von Bean aus XML in Java-Konfiguration
Teilweise Migration von Bean aus XML in Java-Konfiguration
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION