WebService und Synchronisation

alfi82

Mitglied
Hallo Eine Frage,

Ich brauche für einen Verteilte Anwendung ein kleiner Speicher, na ja Speicher ist vielleicht übertrieben eigentlich nur eine HashMap wo die einzelenen Clients etwas eintragen können aus einem bestimmten Grund – ist aber ja nicht so wichtig. Es geht vielmehr um das Thema Synchronisation.

Hier mal der Code von dem WebServiceTest:

Code:
import java.util.HashMap;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

@WebService(name="TestWebService") 
@SOAPBinding(style = SOAPBinding.Style.RPC) 
public class WebServiceTest 
{
	private final int MAX_VIEW_ENTRIES = 50;
	
	HashMap<Integer, Integer> actViewState;
	
	public WebServiceTest() {
		
		System.out.print("Konstruktor Normal");
		
		if(actViewState == null){
			actViewState = new HashMap<Integer, Integer>(MAX_VIEW_ENTRIES);
			for (int i = 1; i < MAX_VIEW_ENTRIES+1; i++) {
				actViewState.put(i, 0);
			}
		}
	}
	
	@WebMethod(operationName="tryToGetView") 
	public synchronized boolean tryToGetView(int clientId, int viewNumber) {
		
		boolean ret = false;
		if(actViewState.get(viewNumber) == 0){
			actViewState.put(viewNumber, clientId);
			ret = true;
		}else{
			ret = false;
		}
		System.out.println("<tryToGetViewNr: "+viewNumber+" , ClientId: "+clientId+">" + " return: "+ret);
		return ret;
	}
	
	@WebMethod(operationName="releaseView") 
	public synchronized boolean releaseView(int clientId, int viewNumber) {
		
		boolean ret = false;
		
		if(actViewState.get(viewNumber) == clientId){
			actViewState.put(viewNumber, 0);
			ret = true;
		}else{
			ret = false;
		}
		System.out.println("<releaseView: "+viewNumber+" , ClientId: "+clientId+">" + " return: "+ret);
		return ret;
	}

}

Auf dem Server wird dann der Web-Services veröffentlicht das geht ja einfach in Java SE 6.

Code:
Endpoint endpoint = Endpoint.publish("http://localhost:8080/servicetest", new WebServiceTest());


In den jeweiligen Clients hole ich mir dann den Webserviceport. Aber wie sieht das mit der Synchronisation aus?
Ich bin mir auch nicht sicher ob es nur eine Instanz von dem WebServiceTest gibt – Habe da auch nichts Richtiges gefunden wo das eventuell erklärt wird.

Existiert da jetzt nur eine Instanz => laut Test müsste es so sein. Reicht das synchronized aus für die Synchronisation ich bin etwas verwirrt seitdem ich das gelesen habe:

http://giu.giustyle.com/06-11-2007-...l-1-monitor-und-das-synchronized-keyword.html

speziell der Punkt: Lost-Update Problem mit synchronized lösen?

Besten Dank schon mal
 
WebServices sollten stateless und damit threadsafe sein. Dein WebService ist es nicht - das sorgt früher oder später für Probleme. Der RPC Style ist ebenfalls "deprecated" - sprich in Realworld Szenarien für ungünstig erwiesen.

Summasummarum: ich würde das so nicht implementieren ;).

Gruß
Ollie
 
Problem ich kann es nicht stateless machen => Ist es besser wenn ich RMI verwende oder wie würde ihr das machen.

Danke
Gruss alfi82
 
Nochwas, also ich habe keine Erfahrung mit WebServices und bin eben nur nach Beispielen und Ebooks vorgegangen - siehe auch hier:

http://weblogs.java.net/blog/vivekp/archive/2006/12/webservices_in.html
http://opentutorial.blogspot.com/2008/01/webservice-in-java-6-jdk-6_06.html

Da der eine Beitrag von 2008 ist und der andere von 2006 dachte ich, dass der Beitrag von 2008 neuer ist, deshalb habe ich es nach diesem Muster implementiert.

Jedefalls habe ich jetzt bei Sun das gefunden:

http://java.sun.com/developer/technicalArticles/J2SE/jax_ws_2/

Ich denke so ist es okay, oder?

Eigentlich muss ich nicht nur ein paar Sachen speichern, sonder eben auch noch etwas Logik usw machen - erfüllen. Ein ServerSocket wollte ich nicht machen wegen dem ganzen Protokoll usw. - RPC fand ich super und es war auch relativ schnell realisiert.

Aber dieses stateless und threadsafe von oben geht mir nicht mehr aus dem Kopf. Ich habe jetzt doch ein etwas komisches Gefühl, dass da mal was schief geht so wie es jetzt läuft.

Deshalb vielleicht nochmals die Frage wie würdet ihr das machen besser mit RMI oder doch mit ServerSockets, oder ?

Gruss alfi82
 
Es geht nicht so sehr darum womit due es implementierst, das Problem ist eher WAS du implementierst. Du hältst und veränderst den Zustand (in) deiner Klasse (deine Variable actViewState). Das ist das "Problem". Angenommen der Server macht jetzt mehrere Instanzen auf und eine Anfrage des CLients landet einmal bei Instanz 1 und einmal bei Instanz 2. Da bekommst du völlig unvorhersehbare Ergebnisse. Transaktionale Datenhaltung wäre halt ein Schritt in die richtige Richtung. Die Frage ist ausserdem, wie oft die Clients anfragen. Wieviele möglicherweis parallel usw.

Gruß
Ollie
 
Danke für die Antwort. Das ist mir jetzt nicht ganz klar: Angenommen der Server macht jetzt mehrere Instanzen auf und eine Anfrage des Client landet einmal bei Instanz 1 und einmal bei Instanz 2 => Wie geht das ? Es gibt ja nur 1 Server und auf dem Server wird der Web-Services veröffentlicht und das ja nur 1 mal (Mit Endpoint usw.).

Wieso könne da mehrere Instanzen entstehen? Oder ist das so, dass wenn mehrere Clients zur selben Zeit Anfragen – der Server für jeden eine neue Instanz anlegt ? Das war mal eine Frage ganz am Anfang ob es eben nur 1 Objekt des Web Service gibt. Wenn nicht verstehe ich jetzt das Problem.

Transaktionale Datenhaltung wäre halt ein Schritt in die richtige Richtung => geht aber nur mit eine Datenbank im Hintergrund oder ?

Im Prinzip brauche ich keine Parallelität. Die Anfragen sind auch nicht sehr häufig vielleicht alle 5 Sekunden oder so, komme aus der Regeltechnik Branche da sind 5 Sekunden eine Ewigkeit.

Also könnte ich es vielleicht so lösen das ich die Daten welche ich im WebService halten möchte static mache? Zudem auch noch ein locking Mechanismus verwende. Zum Beispiel so

private static AtomicBoolean isLocked = new AtomicBoolean();

überprüfen ob isLocked = true
falls nicht auf true setzten,
Jetzt kann darf ich lesen und schreiben sobald der Client fertig ist
setzt dieser isLocked wieder auf false.

Wenn ein Client dran ist und ein weitere eine Anfrage machen möchte muss er warten bis es wieder frei ist. Ein Problem habe ich nur wenn einer abschmiert und das isLocked nicht mehr auf false setzt. Oh je dachte nicht das das so schwierig wird.

Ohne DB wird es keine saubere Lösung geben oder?


Ah jetzt habe ich eine Idee => Ich mache eine Klasse als Singelton auf dem Server dort bau ich die Logik ein und die Datenhaltung mit staischen variablen und Objekten. Den Service verwende ich nur noch um von dieser Klasse zu lesen und zu schreiben also nur noch als Schnittstelle sonst komm ich ja mit dem Client nicht drauf. So müsste es doch gehen oder ?

Danke Gruß alfi82
 
Zuletzt bearbeitet:
Danke für die Antwort. Das ist mir jetzt nicht ganz klar: Angenommen der Server macht jetzt mehrere Instanzen auf und eine Anfrage des Client landet einmal bei Instanz 1 und einmal bei Instanz 2 => Wie geht das ? Es gibt ja nur 1 Server und auf dem Server wird der Web-Services veröffentlicht und das ja nur 1 mal (Mit Endpoint usw.).

Wieso könne da mehrere Instanzen entstehen? Oder ist das so, dass wenn mehrere Clients zur selben Zeit Anfragen – der Server für jeden eine neue Instanz anlegt ? Das war mal eine Frage ganz am Anfang ob es eben nur 1 Objekt des Web Service gibt. Wenn nicht verstehe ich jetzt das Problem.

Wer sagt denn, dass dein Server nur eine Instanz von dem Service anlegt? Das ist in der Spec nicht festgeschrieben. Du hast allerdings soweit recht, dass die meisten Webserver meist nur 1 Instanz erzeugen. Dennnoch läuft jeder Request in einem eigenen Thread. Das heißt, du hast effektiv das gleiche Problem. Du kannst natürlich jede Methode synchronized machen wenn die Performance kein Problem darstellt, allerdings wiederspricht den Einsatzszenario wie schon mehrfach angedeutet eigentlich den Einsatzkriterien für WebServices. Eine Statefull Session Bean oder ein Session Scope Spring Bean sind wohl eher Hämmer mit denen ich danach schlagen würde.

Transaktionale Datenhaltung wäre halt ein Schritt in die richtige Richtung => geht aber nur mit eine Datenbank im Hintergrund oder ?
Ja, irgendwas transaktionales halt. Eine DB scheint aber ein wenig Overhead für dein Anwendungsszenario. Eine InMemory DB könnte man ausprobieren. Die JavaDB vielleicht?

Im Prinzip brauche ich keine Parallelität. Die Anfragen sind auch nicht sehr häufig vielleicht alle 5 Sekunden oder so, komme aus der Regeltechnik Branche da sind 5 Sekunden eine Ewigkeit.
Dann nimm synchronized, schau, dass du einen Server findest, der eine einzelne Instanz sicherstellt und hak das als bösen Hack ab ;). Die einfache new Endpoint Variante halte ich für Produktivszenarien für ungenügend. Das kommt aber auf verschiedene funktionale und nichtfunktionale Anforderungen an.

Also könnte ich es vielleicht so lösen das ich die Daten welche ich im WebService halten möchte static mache? Zudem auch noch ein locking Mechanismus verwende. Zum Beispiel so

private static AtomicBoolean isLocked = new AtomicBoolean();

überprüfen ob isLocked = true
falls nicht auf true setzten,
Jetzt kann darf ich lesen und schreiben sobald der Client fertig ist
setzt dieser isLocked wieder auf false.

Wenn ein Client dran ist und ein weitere eine Anfrage machen möchte muss er warten bis es wieder frei ist. Ein Problem habe ich nur wenn einer abschmiert und das isLocked nicht mehr auf false setzt. Oh je dachte nicht das das so schwierig wird.
Damit programmierst du etwas von Hand was dir ein Container wie Spring oder EJB als Session Scope Components out of the box lieferst. Wenn du gern auf Händen und Knien durch den Matsch watest, nur zu ;). Ich würde die Finger davon lassen.

Ah jetzt habe ich eine Idee => Ich mache eine Klasse als Singelton auf dem Server dort bau ich die Logik ein und die Datenhaltung mit staischen variablen und Objekten. Den Service verwende ich nur noch um von dieser Klasse zu lesen und zu schreiben also nur noch als Schnittstelle sonst komm ich ja mit dem Client nicht drauf. So müsste es doch gehen oder ?
Es ist aus Architektursicht sicher Sinnvoll die eigentliche Logik in Domänenklassen und / oder Services zu verpacken und sie dann durch vorgelagerte Fassaden / Exporter in bestimmte Technologien (so wie du jetzt WebServices) zur Verfügung zu stellen. Damit hast du zum einen "wiederverwendbare" Logik, testbare Logik und wenig bis keinen technischen Code in den Service- bzw. Domänenklassen. Mit den Fassade bzw. Exportern hast du dann Klassen, die die jeweilige Technologie implementieren. Die Idee ist also unabhängig von deinem technischen Problem keine schlechte ;).

Gruß
Ollie
 
Super Danke für die Antwort. Dann mache ich das jetzt so, dass ich eine Singelton neheme auf dem Server => das gibts dann wirklich nur 1 mal. => Und Webservice nur noch als Fassade da ist es dann egal ob es mehrere Instanzen gibt lesen und schreiben müssen sie von dem Singelton.

EJB kenne ich nicht gibts da irgendwo was einfaches für den Anfang.

Danke Gurss
alfi82
 
Zuletzt bearbeitet:
Die einfache new Endpoint Variante halte ich für Produktivszenarien für ungenügend. Das kommt aber auf verschiedene funktionale und nichtfunktionale Anforderungen an.

Gibt es da was besseres? Habe bis jetzt nichts anders gefunden. In sämtlichen Samples wird es so gemacht. Haben Sie vielleicht ein Link oder Beispiel wie man es besser macht.

Danke Gruss
alfi82
 
Zurück