#Enterprise-Java-Technologien verstehen
Dieses Kapitel bündelt die zentralen Legacy-Technologien: EJB, JTA, JMS, SOAP, JSP/Servlet, JPA/JDBC und Security.
#EJB-Lernpfad
#Was du verstehen musst
- Stateless Session Beans
- Stateful Session Beans
- Singleton Beans
- Message Driven Beans
- Local vs Remote Interfaces
- No-interface View
- EJB Lifecycle
- Pooling
- Interceptors
- Timer Services
- Container Managed Transactions
- Bean Managed Transactions
- Security Context
- JNDI Lookups
- EJB Exceptions
#EJB-Analyse-Vorlage
# EJB Analyse: <Klassenname>
## Typ
- Stateless / Stateful / Singleton / MDB:
## Interfaces
- Local:
- Remote:
- No-interface:
## Transaktion
- Default:
- Annotationen:
- REQUIRES_NEW:
- NOT_SUPPORTED:
- setRollbackOnly:
- UserTransaction:
## Dependencies
- @EJB:
- @Resource:
- @PersistenceContext:
- SOAP:
- JMS:
- JNDI:
- Andere:
## Fachliche Verantwortung
- Use Cases:
- Tabellen:
- Events:
- externe Systeme:
## Risiken
- Transaktion:
- externe Calls:
- Side Effects:
- Tests fehlen:
- Migration schwierig wegen:
## Modernisierungsziel
- bleibt vorerst EJB:
- wird dünne Fassade:
- Fachlogik wandert nach:
- Adapter nötig für:
#EJB-Migrationsmuster
Alt:
@Stateless
public class OrderServiceBean {
@PersistenceContext
private EntityManager em;
@EJB
private AuditServiceBean auditService;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void createOrder(CreateOrderRequest request) {
OrderEntity order = new OrderEntity();
order.setCustomerId(request.getCustomerId());
order.setStatus("NEW");
em.persist(order);
auditService.write("ORDER_CREATED");
}
}
Zwischenziel:
public class CreateOrderUseCase {
private final OrderRepository orderRepository;
private final AuditPort auditPort;
public CreateOrderUseCase(
OrderRepository orderRepository,
AuditPort auditPort
) {
this.orderRepository = orderRepository;
this.auditPort = auditPort;
}
public OrderId execute(CreateOrderCommand command) {
Order order = Order.create(command.customerId());
orderRepository.save(order);
auditPort.orderCreated(order.id());
return order.id();
}
}
EJB als dünne Fassade:
@Stateless
public class OrderServiceBean {
@PersistenceContext
private EntityManager em;
@EJB
private AuditServiceBean auditServiceBean;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public OrderId createOrder(CreateOrderRequest request) {
CreateOrderUseCase useCase = new CreateOrderUseCase(
new JpaOrderRepository(em),
new EjbAuditAdapter(auditServiceBean)
);
return useCase.execute(mapToCommand(request));
}
}
#JTA- und Transaktions-Lernpfad
#Was du verstehen musst
- REQUIRED
- REQUIRES_NEW
- MANDATORY
- SUPPORTS
- NOT_SUPPORTED
- NEVER
- Bean Managed Transactions
- Container Managed Transactions
- Rollback bei RuntimeException
- Rollback bei checked Exceptions über
@ApplicationException setRollbackOnly- XA vs non-XA
- Two Phase Commit
- DB + JMS in einer Transaktion
- Transaktionen über Remote Calls
- Lazy Loading und EntityManager Lifecycle
- Self-invocation und Proxy-Grenzen
#Transaction Map Vorlage
# Transaction Map: <Use Case>
## Main Transaction
Start:
- Klasse/Methode:
- TransactionAttribute:
Beteiligte Ressourcen:
- Datasource:
- Persistence Unit:
- JMS Queue/Topic:
- SOAP Calls:
- File/Mail:
DB Writes:
- Tabelle 1:
- Tabelle 2:
Nested Transactions:
- Klasse/Methode:
- Typ:
- Warum?
Rollback:
- RuntimeException:
- Checked Exception:
- @ApplicationException:
- setRollbackOnly:
- manuelles rollback:
Risiken:
- externer Call innerhalb TX:
- lange Locks:
- REQUIRES_NEW:
- XA:
- unklare Exception-Behandlung:
#Mapping EJB zu Spring
TransactionAttributeType.REQUIRED
→ @Transactional(propagation = Propagation.REQUIRED)
TransactionAttributeType.REQUIRES_NEW
→ @Transactional(propagation = Propagation.REQUIRES_NEW)
TransactionAttributeType.NOT_SUPPORTED
→ @Transactional(propagation = Propagation.NOT_SUPPORTED)
TransactionAttributeType.MANDATORY
→ @Transactional(propagation = Propagation.MANDATORY)
TransactionAttributeType.SUPPORTS
→ @Transactional(propagation = Propagation.SUPPORTS)
TransactionAttributeType.NEVER
→ @Transactional(propagation = Propagation.NEVER)
Achtung bei checked Exceptions:
@Transactional(rollbackFor = PaymentFailedException.class)
public void pay(...) {
...
}
#JMS-Lernpfad
#Was du verstehen musst
- Queue vs Topic
- Producer vs Consumer
- MDB
- Redelivery
- Dead Letter Queue
- Acknowledgement
- transaktionale Message-Verarbeitung
- Poison Messages
- Message Selectors
- Correlation ID
- Message ID
- Idempotenz
- Retry-Strategien
- XA mit DB + JMS
#Queue Map Vorlage
# Queue Map
| Queue/Topic | Producer | Consumer | Message Type | Retry | DLQ | Fachlicher Zweck |
|---|---|---|---|---|---|---|
| OrderCreatedQueue | OrderServiceBean | InvoiceMDB | XML | ja? | ja? | Rechnung erzeugen |
#MDB-Migrationsmuster
Alt:
@MessageDriven
public class InvoiceMDB implements MessageListener {
@EJB
private InvoiceServiceBean invoiceServiceBean;
@Override
public void onMessage(Message message) {
invoiceServiceBean.createInvoice(message);
}
}
Zwischenziel:
public class InvoiceMessageHandler {
private final CreateInvoiceUseCase createInvoiceUseCase;
public InvoiceMessageHandler(CreateInvoiceUseCase createInvoiceUseCase) {
this.createInvoiceUseCase = createInvoiceUseCase;
}
public void handle(OrderCreatedMessage message) {
createInvoiceUseCase.execute(
new CreateInvoiceCommand(message.orderId())
);
}
}
MDB bleibt dünn:
@MessageDriven
public class InvoiceMDB implements MessageListener {
private InvoiceMessageHandler handler;
@Override
public void onMessage(Message message) {
OrderCreatedMessage parsed = OrderCreatedMessageMapper.fromJms(message);
handler.handle(parsed);
}
}
#Idempotenz-Tabelle
| Message | Idempotency Key | Prüfung | Aktion bei Duplikat |
|---|---|---|---|
| OrderCreated | orderId | Invoice exists? | ignorieren |
| PaymentCaptured | paymentId | Payment exists? | ignorieren |
| CustomerUpdated | customerId + version | newer version? | alte Version ignorieren |
#SOAP-Lernpfad
#Was du verstehen musst
- WSDL lesen
- XSD Typen
- JAXB-Klassen
- JAX-WS Client
- JAX-WS Endpoint
- SOAP Faults
- WS-Security
- MTOM
- Timeout-Konfiguration
- Contract-first vs Code-first
- Versionierung von XML-Schemas
- generierter Code vs manuell geänderter Code
#SOAP Map Vorlage
# SOAP Services
| Service | Richtung | Klasse | WSDL/XSD | Auth | Timeout | Risiko |
|---|---|---|---|---|---|---|
| CustomerService | Inbound | CustomerEndpoint | customer.wsdl | WS-Security | n/a | hoch |
| PaymentProvider | Outbound | PaymentSoapClient | payment.wsdl | Zertifikat | 30s? | hoch |
#SOAP Adapter Muster
Alt:
@WebServiceRef
private PaymentService paymentService;
public void pay(Order order) {
paymentService.getPaymentPort().charge(...);
}
Besser:
public interface PaymentGateway {
PaymentResult charge(PaymentCommand command);
}
SOAP Adapter:
public class SoapPaymentGateway implements PaymentGateway {
private final PaymentPort port;
public SoapPaymentGateway(PaymentPort port) {
this.port = port;
}
@Override
public PaymentResult charge(PaymentCommand command) {
try {
return map(port.charge(map(command)));
} catch (SOAPFaultException ex) {
throw new PaymentProviderException(ex);
}
}
}
#JSP/Servlet-Lernpfad
#Was du verstehen musst
- JSP Scriptlets
- JSTL
- Custom Tags
- Servlet Filter
- Session State
- Authentication Flow
- CSRF
- serverseitige Formulare
- Businesslogik in JSP
- direkte EJB/JNDI-Zugriffe aus JSP
- Request/Session/Application Scope
#JSP Risikoanalyse
# JSP Risikoanalyse
| JSP | Zweck | Businesslogik? | Nutzt Session? | Ruft EJB/DAO? | Risiko |
|---|---|---|---|---|---|
| createOrder.jsp | Bestellung anlegen | ja | ja | ja | hoch |
| orderList.jsp | Liste anzeigen | nein | ja | nein | niedrig |
#JSP-Migrationsreihenfolge
JSP mit Scriptlets
↓
Servlet/Controller übernimmt Logik
↓
JSP wird reine View
↓
Application Service wird genutzt
↓
REST/API möglich
↓
moderne UI möglich
Alt:
<%
OrderService service = ...
List<Order> orders = service.findOrders();
%>
Besser:
@WebServlet("/orders")
public class OrderServlet extends HttpServlet {
private OrderQueryService orderQueryService;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
req.setAttribute("orders", orderQueryService.findOrders());
req.getRequestDispatcher("/WEB-INF/views/orders.jsp")
.forward(req, resp);
}
}
#JPA/JDBC/Datenbank-Lernpfad
#Was du verstehen musst
- Persistence Units
- EntityManager Lifecycle
- Lazy Loading
- Flush/Commit
- JPQL
- Criteria API
- Native Queries
- Stored Procedures
- DB Trigger
- Views
- Shared Tables
- Optimistic/Pessimistic Locking
- Isolation Levels
- Batch Updates
- Connection Pools
- XA Datasources
#Datenbank-Ownership-Tabelle
# Database Ownership
| Tabelle | Genutzt von | Schreibzugriffe | Kritisch? | Modernisierungsrisiko |
|---|---|---|---|---|
| ORDERS | OrderService, InvoiceMDB | viele | ja | hoch |
| AUDIT_LOG | AuditService | append-only | mittel | niedrig |
| CUSTOMER | CustomerService, CRM Sync | viele | ja | hoch |
#Entity vs Domain
JPA Entity:
@Entity
@Table(name = "ORDERS")
public class OrderEntity {
@Id
private String id;
private String status;
private String customerId;
}
Domain:
public class Order {
private final OrderId id;
private final CustomerId customerId;
private OrderStatus status;
public static Order create(CustomerId customerId) {
return new Order(OrderId.newId(), customerId, OrderStatus.NEW);
}
public void cancel() {
if (status == OrderStatus.SHIPPED) {
throw new OrderCannotBeCancelledException(id);
}
this.status = OrderStatus.CANCELLED;
}
}
#Security-Lernpfad
#Was du verstehen musst
- Container Security
- JAAS / Realm
web.xmlSecurity Constraints@RolesAllowed@PermitAll@DenyAllSessionContext#getCallerPrincipalisCallerInRole- Servlet Filters
- Login Flow
- Session Fixation
- CSRF
- Authorization in JSPs
- Role Mapping im Application Server
#Security Map
# Security Map
| Funktion | Rolle | Prüfung wo? | Mechanismus | Risiko |
|---|---|---|---|---|
| Bestellung anzeigen | USER | web.xml | Container | mittel |
| Bestellung freigeben | MANAGER | EJB SessionContext | manuell | hoch |
| Admin-Seite | ADMIN | JSP/Filter | gemischt | hoch |
Modernisierungsrisiko:
Wenn EJB entfernt wird, gehen eventuell automatisch verloren:
- CallerPrincipal
- Rollenprüfung
- Security Context Propagation
- JAAS Realm Integration