Ganz im Zeichen des “Ease of Development” bringt die neue JDBC Version Annotations mit, die den Zugriff auf Tabellen vereinfachen sollen. Zudem werden auch weitere SQL Features (SQL ROWIDS, SQL/XML) unterstützt.
JAX-WS
Mustang bringt endlich die Webservices in das JDK. Unterstützt werden die neusten W3C und WS-I Standards (SOAP 1.2, WSDL 2.0 und WS-I Basic Profile 1.1). Wie bei JDBC 4.0 werden auch eigene Annotations mitgliefert, die einfachen Zugriff auf Webservices erlauben.
Attach-On-Demand
Dieses Feature erlaubt das Hinzufügen von Debugging, Profiling oder Monitoring-Tools zur Laufzeit und ohne vorherige Angabe von Startup Parametern. Das ist insbesondere für den Serverbereich interessant.
Die JSR 270 ist eine sog. “Umbrella” JSR. Sie definiert nicht selbst die neuen Sprachfeatures von Java 6, sondern referenziert auf eine Sammlung von bestehenden JSRs. Momentan befindet sich JSR 270 im “Early Draft Review” Zustand, d.h. die Featureliste ist noch nicht fixiert. In dieser Postreihe möchte ich paar Features dennoch (ungruppiert) herausgreifen und kurz vorstellen:
GIF Image Writer:
Dank dem Verfall des GIF-Patents erlaubt das javax.imageio Package erlaubt nun auch das Erzeugen von GIF-Bildern. Meiner Meinung kommt das etwas zu spät, das GIF-Format hat in den letzten Jahren enorm an Bedeutung verloren.
Scripting for the Java Platform
Das neue Package javax.script definiert ein Framework zur Anbindung von externe Scriptsprachen. Das gabs bereits schon (z.B. Mozilla Rhino), allerdings eben noch nicht standartisiert.
Verbessertes Zugriff aufs Dateisystem
Bislang konnten Java-Entwickler nur beschränkt Informationen vom Dateisystem erhalten. Nun wird die java.io.File Klasse aufgebohrt, so dass z.B. auch der freie Speicherplatz ermittelt werden kann.
Der Servlet Container Apache Tomcat ist die Referenzimplementierung der Servlet- und JSP-API. In ihm laufen Webapplikationen, die zur Laufzeit installiert (”deployed”) und deinstalliert (”undeployed”) werden können. Damit das funktioniert, muss Tomcat für jede Webapplikation einen eigenen ClassLoader zur Verfügung stellen. Zudem kann es Klassen geben, die von mehreren Webapplikationen gemeinsam verwendet werden.
Tomcat löst diese Anforderungen durch folgende ClassLoader Hierarchie:
Common:
Alle Klassen im /common Verzeichnis des Servers sind sowohl in den Webapplikationen und für Tomcat selbst sichtbar. Hier werden üblicherweise Datenbank-Treiber abgelegt. Entwickler sollten hier keine eigenen JAR-Dateien platzieren, um eventuelle Kompatibilitätskonflikte mit Tomcat zu vermeiden.
Shared:
Die im /shared Verzeichnis befindlichen Klassen stehen allen Webapplikationen zur Verfügung. Sie müssen diese Klassen dann nicht mehr selbst mitbringen. Ein weitere Anwendungszweck ist die Kommunikation zwischen Webapplikationen oder der Einsatz von Singletons, die von mehreren Webapplikationen benötigt werden.
Server:
Die vom Tomcat Server benötigten Klassen befinden sich im /server Verzeichnis. Die Webapplikationen haben keinen Zugriff darauf.
WebApp:
Jede Webapplikation besitzt einen eigenen ClassLoader, der unterhalb vom Shared ClassLoader liegt. Interessant ist, dass hier der Delegationsmechanismus umgekehrt wird:
It is recommended also that the application class loader be implemented so
that classes and resources packaged within the WAR are loaded in preference to
classes and resources residing in container-wide library JARs.
SRV 9.7.2
Auf gut deutsch: Der ClassLoader der Webapplikation versucht zuerst die Klasse zu laden und erst dann wird delegiert. Somit können Webapplikationen Klassen vom Shared oder Common ClassLoader “überschreiben” (z.B. um zu garantieren, dass genau eine bestimmte Version einer Library zum Einsatz kommt).
Mehr zum Thema ClassLoader im Tomcat gibts direkt auf der Tomcat-Homepage. Soweit so gut. Mit diesem Teil ist die ClassLoader – Reihe vorerst abgeschlossen
P.S.: Noch ein Blogtipp von mir: Auf http://leo.freeflux.net/blog gibts ebenfalls interessante Javaartikel.
Ein eigener ClassLoader muss von java.lang.ClassLoader ableiten und sollte die findClass-Methode überschreiben. Diese Methode benötigt den vollständigen Klassennamen und gibt die geladene Klasse in Form eines Class Objektes zurück.
Der nachfolgende ClassLoader MyClassLoader lädt die Klassen aus einem übergebenen Dateipfad. Wie in Java üblich, wird die Packagestruktur auf das Filesystem übertragen (d.h. die Klasse ch.javablog.reloadable.MyTest liegt unter ../ch/javablog/reloadable).
Im Konstruktor von MyClassLoader wird der “parent class loader” übergeben, damit der Delegationsmechanismus funktionieren kann. Erst wenn der “parent class loader” die zu ladende Klasse nicht finden konnte, wird unsere findClass-Methode aufgerufen. Dort lesen wir das “.class”-File ein und erzeugen ein byte-Feld (Zeile 23-29).
Dieses byte-Feld wird für die Methode defineClass der Oberklasse benötigt, denn sie macht die eigentliche Arbeit und generiert aus dem byte-Feld eine Java Klasse
In einer kleinen Main-Methode probieren wir MyClassLoader aus. Wichtig: Die Klasse ch.javablog.reloadable.MyTest befindet sich nicht im CLASSPATH, sondern in dem Verzeichnis “myclasses” (parallel zum “classes” Verzeichnis).
MyClassLoader - loading: .\myclasses\ch\javablog\reloadable\MyTest.class<br /> class ch.javablog.reloadable.MyTest classloader: ch.javablog.MyClassLoader@923e30
Interpretation:
Die MyTest wurde erfolgreich von MyClassLoader geladen. Wenn MyTest weitere Klassen importiert, werden sie ebenfalls von MyClassLoader geladen. Die untere Abbildung zeigt die Position unseres ClassLoaders in der ClassLoader-Hierarchie.
Im nächsten Teil geht es um die ClassLoader im Apache Tomcat, und warum er einen anderen Delegationsmechanismus einsetzt.
Wenn ein Class Loader eine Klasse laden muss, delegiert er die Anfrage zunächst an seinen “parent class loader”. Erst wenn dieser die gewünschte Klasse nicht finden konnte, probiert er es selber die Klasse zu laden. Das testen wir doch gerade mal. Wir schreiben zwei Klassen: Customer und Main. Beide Klassen befinden sich im CLASSPATH. In der main-Methode der Main-Klasse werden folgende Objekte geholt:
ClassLoader des aktuellen Threads
ClassLoader von java.lang.String
ClassLoader von ch.javablog.Main
ClassLoader von ch.javablog.Customer
Alle diese Objekte geben wir auf der Kommandozeile aus.
Interpretation: Der ClassLoader des Threads ist der System ClassLoader (sun.misc.Launcher). Er lädt die String-Klasse nicht selber, sondern delegiert das Laden der String-Klasse an seinen “parent class loader”, dem Bootstrap ClassLoader. Dieser wird nicht als ClassLoader-Objekt repräsentiert, stattdessen wird beim Zugriffsversuch null zurückgegeben.
Die Klassen Customer und Main werden vom System ClassLoader auch an den Bootstrap ClassLoader delegiert. Der kennt sie aber nicht und von daher muss der System ClassLoader diese Klassen selber laden.
Bis jetzt alles noch sehr einfach. Im nächsten Teil schreiben wir einen eigenen ClassLoader…
Jeder kennt Sie, jeder hasst sie: ClassCastException, ClassNotFoundException und NoClassDefFoundError.
Das Laden von Klassen durch ClassLoader erlaubt zwar wunderbare Dinge wie “Hot Deployment” (Dynamisches Austauschen von Klassen zur Laufzeit), sorgt aber auch für eine Reihe von potentiellen Stolpersteinen. Leider stolpert man gerade dann drüber, wenn man überhaupt keine Zeit für Ursachenforschung hat ;). Dewegen gibts hier eine kleine ClassLoader-Einführung.
Eins vorweg: Es gibt zwei Typen von ClassLoader:
There are two types of class loaders: user-defined class loaders and the bootstrap class loader supplied by the Java virtual machine. Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader.
JLS (5.3)
ClassLoader sind hierarchisch aufgebaut. D.h. jeder besitzt genau einen “parent class loader”. Bis auf den “bootstrap class loader”. Denn er steht an der obersten Stelle der ClassLoader-Hierarchie und ist für das Laden der Java API (z.B. String oder Integer) zust�ndig (Konkret lädt er die Klassen aus rt.jar). Unter ihm liegt der erste “user-defined class loader”: Der System ClassLoader. Er lädt die Klassen, die im CLASSPATH angegeben werden.
Das nachfolgende Bild zeigt die ClassLoader-Struktur im einfachsten Fall (keine Sorge, es wird noch komplexer…)
So viel für heute. Im nächsten Teil gehen wir auf den Delegation Mechanismus ein…