⌂ Index
Kapitel 34 · Migration

Legacy-Modernisierung mit Spring: Blueprint für Java EE, EJB, SOAP, JMS und Batch

Typ: FrameworkVersion 2 ausführlich

Dieses Kapitel verbindet die Bausteine zu einem Modernisierungsplan: Legacy verstehen, Grenzen schneiden, Tests aufbauen, Adapter kapseln und schrittweise ersetzen.

Fachliche Einordnung

Spring-Migration ist keine Annotationsersetzung. EJB, JTA, SOAP, JMS, JSP und Batch müssen fachlich verstanden und technisch sicher umgezogen werden.

Enterprise-Merksatz: Dieses Kapitel verbindet die Bausteine zu einem Modernisierungsplan: Legacy verstehen, Grenzen schneiden, Tests aufbauen, Adapter kapseln und schrittweise ersetzen.

Technische Darstellung

Legacy App Gateway Anti-Corruption Layer Spring Modulith Outbox/Event Modern Service
Kernkonzepte
  • Strangler Fig Pattern über Gateway und Anti-Corruption Layer.
  • Ports & Adapters für Legacy-Adapter.
  • Characterization Tests vor Refactoring.
  • Transactional Outbox für Event-Migration.
  • Modulith als Zwischenstufe vor Microservices.
Wann einsetzen?
  • Du migrierst WebSphere/JBoss/GlassFish Anwendungen.
  • Du willst alte SOAP/JMS/Batches in Spring kapseln.
  • Du brauchst einen risikoarmen Phasenplan.
Typische Fehler und Risiken
  • Big Bang Rewrite ohne fachlichen Beweis.
  • Legacy-Datenmodell ungeprüft in neue Services kopieren.
  • Nur technische Migration ohne fachliche Modulgrenzen.
Legacy- und Modernisierungssicht

Phase 1: lesen und testen. Phase 2: Adapter kapseln. Phase 3: neue Use Cases in Spring. Phase 4: Daten- und Eventgrenzen stabilisieren. Phase 5: Legacy Stück für Stück abschalten.

Ausführliches Beispiel

Das Beispiel zeigt bewusst nicht nur Annotationen, sondern auch die Verantwortung der Schicht. In echten Projekten sollte der technische Spring-Code an Adapter- oder Konfigurationsrändern bleiben, während die Fachlogik testbar und möglichst frameworkarm bleibt.

// Ports & Adapters: Domäne kennt SOAP/JMS/JPA nicht.
public interface LegacyCustomerPort {
    CustomerSnapshot findCustomer(String customerNumber);
}

@Component
class SoapLegacyCustomerAdapter implements LegacyCustomerPort {
    private final LegacyCustomerSoapClient client;

    @Override
    public CustomerSnapshot findCustomer(String customerNumber) {
        LegacyCustomerResponse response = client.getCustomer(customerNumber);
        return CustomerMapper.fromLegacy(response); // Anti-Corruption Layer
    }
}

@Service
class ModernOrderUseCase {
    private final LegacyCustomerPort customers;
    private final OrderRepositoryPort orders;

    @Transactional
    public OrderId place(PlaceOrder command) {
        CustomerSnapshot customer = customers.findCustomer(command.customerNumber());
        Order order = Order.placeFor(customer, command.lines());
        orders.save(order);
        return order.id();
    }
}
Checkliste für Reviews
  • Ist die Verantwortung des Bausteins klar: Framework steuert Lebenszyklus, Library wird gezielt benutzt?
  • Ist die Fachlogik außerhalb von Controller, Listener, Repository-Implementierung oder Konfiguration?
  • Sind Fehlerfälle, Timeouts, Security, Monitoring und Tests sichtbar modelliert?
  • Gibt es klare Grenzen zwischen DTO, Domäne, Persistence und Infrastruktur?