J2ME-Objektserialisierung: Frameworks im Vergleich
Transcription
J2ME-Objektserialisierung: Frameworks im Vergleich
AKTUELLE THEMEN DER INFORMATIK J2ME-Objektserialisierung: Frameworks im Vergleich Tobias Satzger, CN8 JUNI 2006 1. Einleitung 2. Objektserialisierung 3. J2ME 4. Aktuelles Thema der Informatik 5. Die Frameworks 5.1 RMI Optional Package 5.1.1 RMI 5.1.2 Java-Standardserialisierung 5.2 Burlap/Hessian 5.2.1 Serialisierung 5.3 Javolution 5.3.1 Serialisierung 5.4 kSOAP 6. Vergleich Frameworks 6.1 Instanzierungszeit 6.2 Serialisierungszeit 6.3 Deserialisierungszeit 6.4 Objektgröße in serialisierter Form 6.5 Objekt-Overhead 7. Quellen S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. S. 3 3 4 5 6 6 6 7 8 8 10 10 11 12 12 13 14 15 15 17 1 Einleitung Dieser Ausarbeitung liegt der gleichnamige Artikel „J2MEObjektserialisierung: Frameworks im Vergleich“ von Reto Bürki, Raffael Schärer und Martin Müller zu Grunde. Dieser Artikel ist in dem Magazin Javaspektrum 1/2006 erschienen. Ursprünglich wollten die Autoren hierbei die 4 frei verfügbaren Frameworks Javolution, kSOAP, Burlap/Hessian und RMI Optional Package miteinander vergleichen. Es wurde eine komplexe Datenstruktur als Testobjekt erstellt, welches jeweils anhand der zu vergleichenden Frameworks sersialisiert wurde. Daraus resultierten einige Ergebnisse, die den Benchmark-Test bildeten. Da das Framework kSOAP nicht in diese Testumgebung integriert werden konnte, kam schließlich ein Vergleich der übrigen 3 Frameworks zustande. 2 Objektserialisierung Die Technik der Objektserialisierung ermöglicht es, in einer Anwendung erzeugte Objekte, persistent abspeichern zu können. Dieses Konzept ist also in einer objektorientierten Programmiersprache sehr interessant, da hier mit eben solchen Ojekten gearbeitet wird. Durch die persistente Speicherung können Objekte später jederzeit durch die abgelegten Daten wieder hergestellt werden – sie überleben auf diese Weise also die Laufzeitumgebung. Außerdem können die serialisierten Daten über das Netzwerk an eine andere Umgebung transportiert werden, um dann dort ein entsprechendes Objekt aus den Daten zu erzeugen – was z.B. gerade für verteilte Anwendungen äußert hilfreich ist. Um mit einem bestimmten Objekt an einer entfernten Stelle weiterarbeiten zu können, ist es für die Anwendung also nicht nötig, abhängig vom aktuellen Kontext, Daten zu identifizieren, die für die diese Situation relevant sind, und diese Daten dann auf irgendeine Weise abzuspeichern und an die entsprechende Stelle im Netzwerk zu schicken. Darüber hinaus müssen die ankommenden Daten noch richtig erkannt und ausgewertet werden können. Bei der Objektserialisierung wird durch den Entwickler einmal festgelegt wie ein serialisierbares Objekt persistent repräsentiert wird, was eine konsistente und einheitliche Methode ohne weitere Umwege darstellt. Die Objektserialisierung ist also in der objektorientierten Welt ein wichtiges Werkzeug. 3 J2ME J2ME steht für Java 2 Mirco Edition. Dies ist eine im wesentlichen starkt abgespeckte Variante der üblichen Standard Edition. Diese limitierte Version kommt daher v.a. auf resourcenarmen Geräten zum Einsatz – z.B. gerade auf mobilen Endgeräten, wie einem Handy. Es gibt für bestimmte Anwendungsbereiche, durch eigens für diesen Zweck bereitstehende Packages, die Möglichkeit den gegebenen Funktionsumfang der Micro Edition bei Bedarft auf kompfortable Weise erweitertn zu können. Dazu gehört z.B. das RMI Optional Package, welches eingangs schon erwähnt wurde und später noch genauer betrachtet wird. Abb. 3-1, www.sun.com 4 Aktuelles Thema der Informatik Die Kombination der Objektserialisierung im Einsatz mit kleinen mobilen Geräten, wird heutzutage schon oftmals verwendet, und wird als zukunfsträchtiges Gebiet angesehen. Dies liegt einerseits sicherlich darin begründet, dass objektorientierte Programmiersprachen in dem Bereich dieser mobilen Geräte immer häufiger zum Einsatz kommen, und dass es abzusehen ist dass diese Tendenz noch weiter zunimmt. Bei einigen Handy-Werbungen werden diese u.A. mit ihrer Java-Fähigkeit angepriesen. Außerdem wird z.B. bei vielen MDE-Geräten, die mit einem Windows-System ausgestattet sind, mit der ebenfalls objektorientierten Sprache C# entwickelt. Andererseits wird den mobilen Anwendungen im Allgemeinen ein enormes Entwicklungspotential zugeschrieben. Viele Geschäftsbereiche, die ihr Dasein noch in einer tristen Offline-Welt verbringen müssen, können damit neu erschlossen werden. Durch die Mobilität der Endgeräte sind deren Einsatzmöglichkeiten nur wenige Grenzen gesetzt. V.a. auch im privaten Sektor sind einige Varianten von mobilen Anwendungen vorstellbar. So sind z.B. Szenarian angedacht, welche das Handy als universelle Fernbedienung im Haushalt – von der Steuerung des Fernsehers bis zur Mikrowelle - sehen. 5 Die Frameworks Bei keinem der zu vergleichenden Frameworks handelt es sich um ein explizit für die Serialisierung entwickeltes Framework. Neben einigen anderen Funktionalitäten kann aber über jedes dieser Frameworks eine Objektserialisierung im J2ME-Umfeld realisiert werden. Im folgenden werden die einzelnen Frameworks näher beschrieben. 5.1 RMI Optional Package Das RMI Optional Package ist eine Erweiterung der J2ME CDC Konfiguration, welches die RMI-Funktionaltät (Remote Method Invocation) hinzufügt (vgl. Abb. 3-1), weil dieses nicht von vornherein bei der Micro Edition vorhanden ist. 5.1.1 RMI RMI ist die Möglichkeit in Java, entfernte Funktionalitäten mit einem hohen Abstraktionnivaeu zu nutzen. Es können Objekte auf einem Server angesprochen werden, als ob diese lokal vorhanden wären. Um entfernte Objekte wie lokale erscheinen zu lassen, wird mit sog. Stellvertreterobjekten bzw. Proxies gearbeitet. Lokal kann so z.B. eine Methode des Proxy-Objekts ausgeführt, und das Ergebnis zurückerhalten werden. Die Berechnung des Ergebnisses wird tatsächlich aber an anderer Stelle durchgeführt. Das Stellvertreterobjekt leitet die Anfrage nämlich seinerseits an die entsprechende Stelle weiter, und gibt schließlich das erhaltene Resultat an den Aufrufer zurück. Innerhalb der Methode des Stellvertreter wird also nicht das eigentliche Funktionsangebot ausgeführt, sondern die Kommunikation, um die eigentliche Funktion an jener entfernten Stelle abarbeiten zu lassen, wo sie implementiert wurde. Der Client nutzt die Proxy-Objekte lokal, ohne sich dafür interessieren zu müssen wo letztendlich die Arbeit verrichtet wird. 5.1.2 Java-Standardserialisierung Die Proxy-Objekte müssen natürlich auch die Ein-/ Rückgabeobjekte an die/von den entfernten Objekte weiter-/ zurückgeben, die für bestimmte Methoden erforderlich sind. So muss beispielsweise ein String-Objekt „person“ bei folgender Beispiel-Methode über das Netzwerk gesendet werden: public int getId(String person) Listing 5.1.2-1 Hierbei spielt die Objektserialisierung eine tragende Rolle bei RMI. Diese ermöglicht es Objekte in ein persistentes Format zu bringen, welches schließlich über das Netzwerk gesendet werden kann. An der Gegenstelle werden die Objekte dann per Deserialisierung restauriert. Der RMI-Mechanismus greif dabei auf die JavaStandardserialisierung (Java Object Serialization – JOS) zurück, welche die Objekte in ein binäres Format ablegt. Ein Objekt kann anhand der writeObject-Methode der ObjectOutputStream-Klasse auf diese Weise serialisiert werden. Der ObjectoutputStream-Klasse wird der OutputStream übergeben, in welche das Objekt geschrieben werden soll. Um in der Welt von RMI zu bleiben, soll dies ein NetzwerkDatenstrom sein: String person = „Person“; // Netzwerk-Ausgangsstrom Socket socket = new Socket(host, port); OutputStream socketOutStream = socket.getOutputStream(); // Verbindung zw. Objekt-Ausgangsstrom und Netzwerk-Strom herstellen ObjectOutputStream objOutStream = new ObjectOutputStream(socketOutStream); // serialisieren objOutStream.writeObject(person); Listing 5.1.2-2 Um Objekte serialisieren zu können, müssen diese die Markierungsschnittstelle Serializable implementieren. Die Klasse String aus Listing 5.1.2-2 erfüllt diese Anforderung, wie auch viele andere der vordefinierten Klassen. Es gibt allerdings auch Exemplare, welche diese Implementierung nicht aufweisen, weil deren Serialisierung u.U. auch gar nicht klar wäre. Z.B. ist dies bei der Klasse Thread der Fall. Soll eine eigene Klasse serialisiert werden können, muss diese also ebenfalls Serializable sein. Wird ein Objekt serialisiert, so müssen auch all deren Attribute mit abgespeichert werden, damit das Objekt bei der Wiederherstellung den abzuspeichernden Zustand wieder annehmen kann. Bei der Standardserialisierung wird deshalb der gesamte Objektbaum durchlaufen, damit keine relevanten Daten aussen vor gelassen werden. Der Entwickler kann bei seinen Klassen auch selbst hinterlegen, welche Ausgabe deren Objekte bei der Serialisierung erzeugen und wie entsprechend bei der Deserialisierung vorgegangen wird. 5.2 Burlap/Hessian Burlap und Hessian sind zwei Protokolle, um Web Service verbinden zu können. Die beiden Varianten unterscheiden sich dadurch, dass Burlap durch die Serialisierung ein XML-Format erzeugt und Hessian hingegen ein binäres Format. Für dieses Protokolle sind Implementierungen für verschiedene Plattformen verfügbar (Java, Python, C++, .NET C#, PHP, Ruby). Die Protokolle weisen ebenfalls eine geringe Grösse auf und eignen sich daher für den Einsatz auf J2ME-Umgebungen. 5.2.1 Serialisierung Dieses Framework unterstützt die Java-Serialisation und erfordert daher nicht das Ausgabeformat explizit festzulegen. Alle üblichen Java-Klassen können auch mit Burlap/Hessian serialisiert werden. Der Serialisierungvorgang wird analog zu dem aus der JavaStandardserialisierung angestossen (vgl. 5.1.2-2). Das Objekt ObjectoutputStream wird aber – je nach Variante – durch ein HessianOutput- bzw. BurlapOutput-Objekt ersetzt: String person = „Person“; // Netzwerk-Ausgangsstrom Socket socket = new Socket(host, port); OutputStream socketOutStream = socket.getOutputStream(); // Verbindung zw. Objekt-Ausgangsstrom und Netzwerk-Strom herstellen HessianOutput hessianOut = new HessianOutput(socketOutStream); // serialisieren hessianOut.writeObject(person); Listing 5.2.1-1 // ... BurlapOutput burlapOut = new BurlapOutput(socketOutStream); // ... Listing 5.2.1-2 Die binäre Version Hessian kann sogar mit einer kompakten Micro-Variante genutzt werden. Diese Variante kann mit Hilfe von nur 5 Hessian-Klassen verwendet werden, was sich z.B. v.a. bei dem Einsatz auf Handys eignet. Das folgende Beispiel der Hessian-Dokumentation zeigt, wie somit ein entfernter Service genutzt werden kann: Abb. 5.2.1-3 5.3 Javolution Dieses Framework ist hauptsächlich für Echtzeit- und EmbeddedSysteme gedacht. So werden mit diesem Framework einige Klassen ausgeliefert, die gegenüber den bestehenden Klassen der Java Mirco bzw. Standard Edition so manche Vorteile v.a. hinsichtlich der Geschwindigkeit versprechen. In der Dokumentation der Javolution Klasse FastTable ist folgender Vergleich zu finden: Abb. 5.3-1, www.javolution.org U.a. besitzt Javolution einen sehr schnellen XML-Parser, der hinsichtlich der Serialisierung noch von Interesse sein wird. Das Framework kann sowohl auf der Mirco wie auch in Verbindung mit der Standard Edition verwendet werden. 5.3.1 Serialisierung Die Serialisierung, wie es dieses Framework vorsieht, geschieht über die Methode write, der Javolution-Klasse ObjectWriter. An diese Methode wird das zu serialisierende Objekt übergeben, sowie der OutputStream, in welches die Daten geschrieben werden: String person = „Person“; // Netzwerk-Ausgangsstrom Socket socket = new Socket(host, port); OutputStream socketOutStream = socket.getOutputStream(); // serialisieren ObjectWriter<String> personWriter = new ObjectWriter<String>(); personWriter.write(person, socketOutStream); Listing 5.3.1-1 Im inneren der write Methode wird nach einem eigenen Format serialisiert, welches durch ein XMLFormat-Objekt von Javolution festgelegt ist. Jeder Klasse kann dabei ein eigenes XMLFormat-Objekt zugeordnet werden. In der Dokumentation von Javolution wird empfohlen ein XMLFormat für eine eigene Klasse über eine statische Instanz festzulegen. Beispielhaft soll dies anhand der Klasse Point veranschaulicht werden: Abb. 5.3.1-2, www.javolution.org Ist zu einer Instanz einer bestimmte Klasse kein entsprechendes XMLFormat-Objekt vorhanden, so wird innerhalb des Schreibvorgangs ein passendes XMLFormat innerhalb der Vererbungshierarchie gesucht. Letzten Endes kann immer noch das XMLFormat der Klasse Object herangezogen werden, welches aber keine Standardserialisierung durchführt. Bei dem Serialisierungsvorgang wird also schließlich – dem festgelegten Format entsprechend – ein XML-Dokument erzeugt, welches dann das Objekt repräsentiert. Wie einleitend schon angedeutet wird intern ein XML-Parser des JavolutionFrameworks verwendet, um das Dokument zu erstellen und auszuwerten. 5.4 kSOAP Wie der Name bereits vermuten lässt verwendet dieses Framework den Standard SOAP. Dieser ist – neben RMI – auch eine Methode um die Kommunikation von verteilten Anwendungen zu realisieren. SOAP verwendet dabei die etablierten Web-Standards HTML und XML. Viele existierende SOAP-Frameworks können bei mobilen Anwendungen nicht eingesetzt werden, weil diese schlicht die Speichergrösse der üblichen Geräte sprengen. kSOAP ist deshalb gerade für den Einsatz mit der Java Micro Edition entwickelt worden und umgeht diese Problematik daher vom Ansatz her. Da kSOAP – wie bereits erwähnt – nicht in die Testumgebung integriert werden konnte, ist leider kein Vergleich zu den anderen Frameworks möglich gewesen. 6 Vergleich der Frameworks Zur Durchführung der Tests wurde folgendes Referenzobjekt angelegt: Abb. 6-1 Darauf basierend wurden die Test durchgeführt, die in 6.1 – 6.5 aufgeführt sind. Die Erklärungen hierzu wurden aus dem Artikel entnommen. 6.1 Instanzierungszeit Die Instanzierungszeit (in Nanosekunden) „bezeichnet die Zeit, die zur Instanzierung des komplexen Objektes benötigt wird. Abb. 6.1-1: Instanzierungszeit „Bei der Instanzierungszeit fiel vor allem auf, dass die Virtuelle Maschine eine gewisse Anlaufzeit bei der Objektinstanzierung benötigt und dort die Werte entsprechend hoch ausfallen. Dies lässt sich darauf zurückführen, dass der Just in Time Compiler (JIT) bei der ersten Instanzierung des Objektes zuerst aus dem Java-Bytecode ausführbaren Maschinencode generieren muss. Bei weiteren Instanzierungen des Objektes wird dieser Schritt nicht mehr benötigt, da der Maschinencode im Speicher schon vorhanden ist. Hessian und Burlap (s. Abb. 6.1-1) scheiden fast gleich ab, was nicht verwundert, da diese Frameworks die gleichen Objektdefinitionen verwenden. Javolution erzeugt eindeutig die schwergewichtigsten Objekte, die einen sehr hohen Instanzierungszeit vor allem bei der ersten Instanzierung benötigt. Dies liegt daran, dass das Framework zuerst die Formatierungsinformationen für die jeweiligen Objekte verarbeiten muss.“ 6.2 Serialisierungszeit Die Serialisierungszeit (in Millisekunden) „bezeichnet die Zeit,die nötig ist, um das Objekt vom Speicher in einen Strom zu serialisieren.“ Abb. 6.2-1: Serialisierungszeit „Bei diesem Test fällt vor allem auf, dass Javolution sehr schnell serialisiert, obwohl es XML als Darstellungsform für die Serialisierung verwendet (s. Abb. 6.2-1). Javolution serialisiert Objekte fast gleich schnell wie RMI, das seine Objekte in optimierter, binärer Form speichert. Diese Messungen stimmen auch mit den Ergebnissen der Benchmarks der Javolution-Entwickler überein. Was das Framework bei der Instanzierung der Objekte durch die Formatierungsinformationen verliert, macht es bei der Serialisierung wieder gut. Anders als bei Burlap und Hessian steigt bei RMI und Javolution die Zeit für die Objektserialisierung nicht an, obwohl die Größe der Objekte massiv zunimmt. Hessian und Burlap zeigen einen linearen Anstieg der Serialisierungszeit, wobei Burlap aufgrund der XML-Codierung langsamer ist. Am schnellsten serialisiert RMI die Objekte. Die hohe Performance von RMI fällt in allen Tests auf. Die liegt vor allem an den effizienten Algorithmen und der optimalen Ausnutzung der Funktionalität von Java.“ 6.3 Deserialisierungszeit Die Deserialisierungszeit „bezeichnet die Zeit, die das jeweilige Framework benötigt, um das serialisierte Objekt wieder aus dem Strom zu deserialisieren.“ „Das Resultat dieses Tests ist analog zum Resultat des Tests Serialisierungszeit. Wieder glänzen Javolution und RMI mit konstanten Zeiten, obwohl die Objektkomplexität zunimmt. Auch Hessian und Burlap verhalten sich analog.“ 6.4 Objektgrösse in serialisierter Form Die Objektgrösse in serialisierter Form (in Kilobytes) „bestimmt die Größe, die das Objekt in serialisierter Form im Strom benötigt.“ Abb. 6.4-1: Objektgrösse in serialisierter Form „In Abbildung 6.4-1 fällt auf, dass trotz zunehmender Objektgrösse bei RMI die Größe der Daten in serialisierter Form nicht in gleichem Maße zunimmt wie bei den anderen drei getesteten Frameworks. Burlap schneidet auch hier am schlechtesten ab. Die liegt daran, dass Burlap SML (Simple Markup Language, einfacheres XML) für die Darstellung der serialisierten Daten verwendet. Dies verursacht längere Tags und Redundanzen durch Wiederholung. Hier zeigt sich eindeutig, dass die binären Protokolle in dieser Disziplin klar überlegen sind, da diese Darstellung deutlich kürzere Identifikationstags erzeugt. Anstatt <Integer> zum Bezeichnen eines Integer-Wertes reicht bei Hessian ein I.“ 6.5 Objekt-Overhead Der Objekt-Overhead (in Kilobytes in %) „bestimmt den Overhead des Objektes. Der Overhead berechnet sich aus der Differenz der Objektgröße im Arbeitsspeicher zur Objektgröße in serialisierter Form.“ Abb. 6.5-1: Objekt-Overhead „Abbildung 6.5-1 zeigt, dass auch hier die Frameworks effizienter sind, die binäre Technik verwenden. Ein interessanter Effekt stellt sich bei RMI ein, bei dem der Overhead mit zunehmender Objektkomplexität abnimmt. RMI ersetzt beim Marshalling Objekte mit gleichem Inhalt durch Referenzen, was zu einer sehr kompakten Darstellung führt. An der Spitze liegt RMI mit einem sinkenden Overhead. Der unter den Nullpunkt sinkende Wert bedeutet, dass bei RMI mit zunehmender Objektgrösse die Darstellung im serialisierter Form kleiner ist als die Größe des Objekts im Speicher. Man kann hier also von einer Kompression der serialisierten Daten sprechen. Hessian weist einen Overhead von ca. 26 % auf. Das heißt, ungefähr ein Viertel des serialisierten Datenvolumens wird vom Protokoll beansprucht. Die beiden XML-basierte Protokolle weisen einen hohen Overhead von 50 % (Javolution) bis 61 % (Burlap) auf.“ 7 Quellen • R. Bürki, R Schärer, M. Müller: J2ME-Objektserialisierung: Frameworks im Vergleich, Javaspektrum 1/2006 • [Hessian/Burlap] www.caucho.com • [Javolution] www.javolution.org • [kSOAP] kobjects.sourceforge.net/ksoap2 • www.sun.com • J. Zobel, Mobile Business und M-Commerce, Hanser 2001 • C. Ullenboom: Java ist auch eine Insel