In einer älteren Struts 1.x Webanwendung gab es Probleme mit
Speicherlecks. Im Laufe der Analyse stieß ich auf die Klasse
org.apache.struts.action.RequestProcessor. Sie instanziiert bei Bedarf
die Actionklassen, speichert sie zwischen und verwendet diese Instanzen
für eingehende Requests wieder. Das Problem der Webanwendung bestand
darin, dass am Ende der Requestverarbeitung die Daten der Actionklassen
(große ResultSets aus SQL Statements ect.) nicht sauber aufgeräumt
wurden. Da die Actionklasseninstanzen vom RequestProcessor weiter
gehalten werden, greift die Garbage Collection nicht. Somit verbrauchte
jede Actionklasse sehr viel Speicher für veraltete Daten. Außerdem waren
die Klassen entgegen des Hinweises
in der Dokumentation (siehe Kapitel 4.4.1) nicht thread-safe. Dies
machte sich durch Exceptions (z.B.:
java.util.ConcurrentModificationException) bzgl. konkurrierender
Zugriffe auf Daten der Actionklassen bemerkbar. Durch die große Anzahl
der Actionklassen war eine Analyse / Überarbeitung jeder Klasse nicht
möglich. Daher bestand die einfachste Lösung darin, dem RequestProcessor
das Cachen und die Wiederverwendung der Actioninstanzen abzugewöhnen:
- Eine eigene Klasse anlegen, die von org.apache.struts.action.RequestProcessor erbt:
public class MyRequestProcessor extends RequestProcessor - Methode protected Action processActionCreate(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException überschreiben und das speichern der Instanzen deaktivieren.
- Nun muss man Struts sagen, dass der eigene RequestProcessor verwendet werden soll. Hierzu muss folgender Eintrag in der struts-config.xml vorgenommen werden:
<controller processorClass="de.mnau.mypackage.MyRequestProcessor"/>