2013-07-20 8 views
8

Ich habe eine Einzelinstanzklasse, die ExceptionMapper implementiert. Es ist keine statische Klasse, aber es ist eine Klasse, für die ich weiß, dass nur eine einzelne Instanz erstellt wird (ich habe überprüft - Konstruktor wird nur einmal aufgerufen).JAX-RS (Jersey) ExceptionMapper - @Context-Injektion in statische/Singleton-Klasse - es funktioniert, aber warum?

Meine Klasse verwendet @Context HttpServletRequest, und das kann ich klar beobachten, wenn meine ExceptionMapper.toResponse() Methode aufgerufen wird, die @Context ‚request‘ Parameter hat einen Wert, der für eine Anforderung relevant ist wo die Ausnahme ausgelöst wird.

The doc says Dies ist in der Tat von Design-unterstützte Funktion und dass es durch die Verwendung von "Proxies" getan wird.

Ich frage mich, wie genau das implementiert ist - wie eine einzelne Instanz kann verschiedene Member Variablenwerte gleichzeitig haben?

Danke,
AG

PS: hier ist der Code-Test:

@Provider 
public class MyExceptionMapper implements ExceptionMapper<Exception> { 

    public MyExceptionMapper() { 
     System.out.println("CTOR!!"); 
    } 

    @Context HttpServletRequest req; 

    public static boolean done = false; 
    public Response toResponse(Exception ex) { 
     if (!done) { 
      done = true; 
      Thread.sleep(10000); 
     } 
     System.out.println(req.getRequestURI()); 
     return null; 
    } 
} 

Ausnahme Mein REST-Handler-Methode löst, so dass, wenn ich die folgenden zwei Anfragen "parallel" ausführen (der Schlaf oben stellt sicher, dass zuerst ein nicht beendet ist, wenn der zweite kommt man und IMHO sollte die one-and-only 'req' Feld) ändern:

- http://localhost/app/one 
- http://localhost/app/two 

mein Programm druckt:

CTOR! 
http://localhost/app/one 
http://localhost/app/two 

Antwort

5

Die einfachste Methode zur Erreichung des Effekts, den Sie beobachten für das injizierte HttpServletRequest Objekt ist, um tatsächlich ein Proxy-Objekt, ein Thread-aware Delegat für die echtenHttpServletRequest sein. Wenn Sie Methoden für den Delegaten aufrufen, suchen sie nur nach dem korrekten realen Objekt (z. B. über eine lokale Threadvariable) und leiten den Aufruf an diesen weiter. Diese Strategie ist relativ einfach zu bekommen, und da es sich um eine Schnittstelle handelt, müssen wir uns definitiv keine Gedanken über Feldzugriffe machen (die für die Proxy-Erstellung etwas komplizierter sind).

Es gibt verschiedene Möglichkeiten, ein solches Proxy-Objekt zu erstellen. Insbesondere könnte dies durch direktes Implementieren der Schnittstelle erfolgen, oder es könnte generischer über das Java general dynamic proxy mechanism (das einen Proxy für jede Schnittstelle aufbauen kann) erfolgen. Es gibt andere ausgefeiltere Möglichkeiten wie die Generierung von Laufzeitcode, aber sie sind hier nicht notwendig. OTOH, ich wäre überhaupt nicht überrascht, wenn direkt implementiert wurde; es ist eine etwas wichtige Klasse für eine JAX-RS-Implementierung ...

Verwandte Themen