Spring / Quarkus / Jakarta EE Migration · Stand 2026-07-07

10 Java Enterprise Migration auf OpenShift

Legacy-Java-Systeme sollten selten per Big Bang migriert werden. Besser ist fachliches Schneiden, Adapter, Contract Tests, Strangler Fig und schrittweise Containerisierung.

Diagramm zu 10 Java Enterprise Migration auf OpenShift
Kompakte fachliche und technische Darstellung.

Ausgangslage

Typische Legacy-Landschaft: WebSphere Traditional, Java 8, EAR, EJB, SOAP, JMS, JTA, JSP/JSF, Oracle, Stored Procedures und Batchjobs.

OpenShift löst diese fachliche Komplexität nicht automatisch. Es liefert aber eine Plattform, um Teile kontrolliert neu zu bauen, zu betreiben und zu messen.

Migrationsstrategie

Lift and Shift nur als Zwischenstufe, wenn Risiko reduziert und Betrieb stabilisiert wird.

Strangler Fig: neue fachliche Funktionen werden vor das Alt-System gesetzt und schrittweise herausgeschnitten.

Adapter Pattern schützt neue Domäne vor alten SOAP-/DTO-/Datenbankmodellen.

Contract Tests sichern Schnittstellen, bevor Traffic umgeschaltet wird.

Java Runtime Entscheidung

Spring Boot: große Ökosystembreite, viele Enterprise-Teams kennen es.

Quarkus: containerfreundlich, schnelle Starts, geringer Speicherbedarf, gute Kubernetes-/OpenShift-Integration.

Jakarta EE/MicroProfile: gute Wahl, wenn Standards und App-Server-Nähe wichtig sind.

Ausführliches Enterprise-Beispiel

Das Beispiel folgt einer fiktiven Shop-Landschaft mit order-api, billing-api, payment-api, portal-ui, Batch-Export und Messaging. Der Fokus liegt auf sauberem Verständnis statt auf blindem Kopieren.

Fachlicher Ablauf

  1. Kunde bestellt über Portal.
  2. order-api validiert Auftrag.
  3. billing-api erzeugt Rechnung.
  4. payment-api prüft Zahlung.
  5. Events informieren Lager und Reporting.

Technischer Ablauf

  1. Route nimmt HTTPS an.
  2. Service verteilt auf Pods.
  3. Pods lesen ConfigMaps und Secrets.
  4. Readiness schützt Rollout.
  5. Monitoring misst Fehlerquote und Latenz.

Konfigurations- und Codebeispiele

JAVA

// Pattern: Adapter - kapselt altes SOAP-Modell hinter moderner Domänenschnittstelle.
// Pattern: Circuit Breaker - verhindert Kaskadenausfälle bei instabilem Legacy-System.
public final class LegacyBillingAdapter implements BillingPort {
    private final SoapBillingClient soapClient;
    private final CircuitBreaker circuitBreaker;

    public LegacyBillingAdapter(SoapBillingClient soapClient, CircuitBreaker circuitBreaker) {
        this.soapClient = soapClient;
        this.circuitBreaker = circuitBreaker;
    }

    @Override
    public Invoice createInvoice(Order order) {
        return circuitBreaker.executeSupplier(() -> {
            LegacyInvoiceRequest request = LegacyInvoiceMapper.fromDomain(order);
            LegacyInvoiceResponse response = soapClient.createInvoice(request);
            return LegacyInvoiceMapper.toDomain(response);
        });
    }
}

DOCKER

FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:latest
WORKDIR /deployments
COPY target/quarkus-app/lib/ ./lib/
COPY target/quarkus-app/*.jar ./
COPY target/quarkus-app/app/ ./app/
COPY target/quarkus-app/quarkus/ ./quarkus/
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError"
EXPOSE 8080
USER 185
CMD ["java", "-jar", "quarkus-run.jar"]

YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-api
  labels:
    app: order-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-api
  template:
    metadata:
      labels:
        app: order-api
    spec:
      serviceAccountName: order-api-sa
      containers:
        - name: order-api
          image: image-registry.openshift-image-registry.svc:5000/shop/order-api:1.0.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 250m
              memory: 512Mi
            limits:
              cpu: 1000m
              memory: 1024Mi
          readinessProbe:
            httpGet:
              path: /q/health/ready
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /q/health/live
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 20

Typische Fehlerbilder und Diagnose

Pending Pods

Prüfe Ressourcen, Node-Selector, Taints, PVC und Quotas. Nicht sofort am Java-Code suchen.

CrashLoopBackOff

Prüfe Logs des vorherigen Containers, Config/Secrets, Port, JVM Memory und Health Endpoints.

Route erreichbar, App nicht

Prüfe Service-Selector, Endpoints, Readiness, TLS-Termination und NetworkPolicy.

Praxisaufgabe

Wähle eine Legacy-Funktion, etwa Rechnung erzeugen. Schneide sie fachlich, erstelle Adapter, Contract Test, neues REST-API und eine Route. Leite erst 5 Prozent Traffic um.

Merksätze

  • Deklarativer Zustand ist wichtiger als manuelle Serveränderung.
  • Security und Betrieb gehören von Anfang an zum Deployment.
  • Jede YAML-Datei ist Architekturentscheidung und sollte reviewbar sein.
  • Produktionsreife entsteht durch Messbarkeit, Rollback und klare Ownership.