Ortunabhängiger Zugriff auf Ressourcen

  • Übersicht
  • Ressourcen, Namen und Kontexte
  • Systemressourcen
  • Nicht-Systemressourcen
  • Ressourcennamen
  • Verwendung von Methoden von java.lang.Class
  • Verwendung von Methoden von java.lang.ClassLoader
  • Sicherheit
  • Beispiele

Überblick

Eine Ressource sind Daten (Bilder, Audio, Text usw.), auf die ein Programm unabhängig vom Ort des Programmcodes zugreifen muss. Java-Programme können zwei Mechanismen für den Zugriff auf Ressourcen verwenden: Applets verwenden Applet.getCodeBase(), um die Basis-URL für den Applet-Code zu erhalten und erweitern dann die Basis-URL mit einem relativen Pfad, um die gewünschte Ressource zu laden, zum Beispiel mit Applet.getAudioClip(url). Anwendungen verwenden „bekannte Orte“ wieSystem.getProperty("user.home") oderSystem.getProperty("java.home"), fügen dann“/lib/resource“ hinzu und öffnen diese Datei.

Methoden in den Klassen Class undClassLoader bieten eine ortsunabhängige Möglichkeit, Ressourcen zu lokalisieren. Sie ermöglichen zum Beispiel das Auffinden von Ressourcen für:

  • Ein Applet, das über mehrere HTTP-Verbindungen aus dem Internet geladen wurde.
  • Ein Applet, das über JAR-Dateien geladen wurde.
  • Eine Java Bean, die in den CLASSPATH geladen oder installiert wurde.
  • Eine „Bibliothek“, die im CLASSPATH installiert wurde.

Diese Methoden bieten keine spezielle Unterstützung für das Auffinden lokalisierter Ressourcen. Lokalisierte Ressourcen werden von den Internationalisierungsfunktionen unterstützt.

Ressourcen, Namen und Kontexte

Eine Ressource wird durch eine Zeichenkette identifiziert, die aus einer Folge von Teilstrings besteht, die durch Schrägstriche (/) getrennt sind, gefolgt von einem Ressourcennamen.Jeder Teilstring muss ein gültiger Java-Bezeichner sein. Der Ressourcenname hat die Form shortName odershortName.extension. SowohlshortName als auch extension müssen Java-Bezeichner sein.

Der Name einer Ressource ist unabhängig von der Java-Implementierung; insbesondere ist das Pfad-Trennzeichen immer ein Schrägstrich(/). Die Java-Implementierung steuert jedoch die Details, wie der Inhalt der Ressource in eine Datei, eine Datenbank oder ein anderes Objekt, das die eigentliche Ressource enthält, abgebildet wird.

Die Interpretation eines Ressourcennamens ist relativ zu einer Classloader-Instanz. Methoden, die von der KlasseClassLoader implementiert werden, führen diese Interpretation durch.

Systemressourcen

Eine Systemressource ist eine Ressource, die entweder in das System eingebaut ist oder von der Host-Implementierung gehalten wird, zum Beispiel in einem lokalen Dateisystem. Programme greifen auf Systemressourcen über dieClassLoader-Methoden getSystemResource undgetSystemResourceAsStream zu.

Zum Beispiel kann das Auffinden einer Systemressource in einer bestimmten Implementierung das Durchsuchen der Einträge im CLASSPATH beinhalten. DieClassLoader-Methoden durchsuchen jedes Verzeichnis, jede ZIP-Datei oder jeden JAR-Datei-Eintrag im CLASSPATH nach der Ressourcendatei und geben, wenn sie gefunden werden, entweder ein InputStream oder den Ressourcennamen zurück. Wenn nicht gefunden, geben die Methoden null zurück. Eine Ressource kann in einem anderen Eintrag im CLASSPATH gefunden werden als der Ort, an dem die Klassendatei geladen wurde.

Nicht-System-Ressourcen

Die Implementierung von getResource bei einem Klassenlader hängt von den Details der ClassLoader Klasse ab. Beispiel: AppletClassLoader:

  • Erst wird versucht, die Ressource als Systemressource zu lokalisieren; dann, wenn sie nicht gefunden wird,
  • Sucht die Ressourcen in Archiven (JAR-Dateien), die bereits in diese CODEBASE geladen wurden; dann, wenn sie nicht gefunden wird,
  • Verwendet CODEBASE und versucht, die Ressource zu lokalisieren (was die Kontaktaufnahme mit einem entfernten Standort beinhalten kann).

Alle Klassenlader suchen zuerst nach einer Ressource als Systemressource, analog zur Suche nach Klassendateien. DieseSuchregel erlaubt das lokale Überschreiben jeder Ressource. Clients sollten einen eindeutigen Ressourcennamen wählen (z.B. mit dem Firmen- oder Paketnamen als Präfix).

Ressourcennamen

Eine übliche Konvention für den Namen einer Ressource, die von einer Klasse verwendet wird, ist es, den voll qualifizierten Namen des Pakets der Klasse zu verwenden, aber alle Punkte (.) in Schrägstriche (/) umzuwandeln, und einen Ressourcennamen der Form name.extension hinzuzufügen. Um dies zu unterstützen und um die Handhabung der Details von Systemklassen zu vereinfachen (für diegetClassLoader null zurückgibt), bietet die KlasseClass zwei Komfortmethoden, die die entsprechenden Methoden in ClassLoader aufrufen.

Der Ressourcenname, der einer Class-Methode gegeben wird, kann ein beginnendes „/“ haben, das ihn als „absoluten“ Namen kennzeichnet.Ressourcennamen, die nicht mit einem „/“ beginnen, sind „relativ“.

Absolute Namen werden von ihrem anfänglichen „/“ befreit und ohne weitere Änderung an die entsprechendeClassLoaderMethode weitergegeben, um die Ressource zu finden. Relative Namen werden entsprechend der zuvor beschriebenen Konvention modifiziert und dann an eine ClassLoader-Methode übergeben.

Verwendung von Methoden von java.lang.Class

Die Klasse Class implementiert mehrere Methoden zum Laden von Ressourcen.

Die Methode getResource() gibt eine URL für die Ressource zurück. Die URL (und ihre Darstellung) ist spezifisch für die Implementierung und die JVM (d.h. die in einer Laufzeitinstanz erhaltene URL funktioniert möglicherweise nicht in einer anderen). Das Protokoll ist normalerweise spezifisch für das ClassLoader, das die Ressource lädt. Wenn die Ressource nicht existiert oder aus Sicherheitsgründen nicht sichtbar ist, geben die Methoden null zurück.

Wenn der Client-Code den Inhalt der Ressource als InputStream lesen will, kann er die Methode openStream() auf die URL anwenden. Das ist häufig genug, um das Hinzufügen von getResourceAsStream() zuClass und ClassLoader zu rechtfertigen.getResourceAsStream() ist dasselbe wie der Aufruf vongetResource().openStream(), außer dassgetResourceAsStream() IO-Ausnahmen abfängt und einen leeren InputStream zurückgibt.

Client-Code kann den Inhalt der Ressource auch als Objekt anfordern, indem er die java.net.URL.getContent()Methode auf die URL anwendet. Dies ist nützlich, wenn die Ressource z. B. die Daten eines Bildes enthält. Im Falle eines Bildes ist das Ergebnis ein awt.image.ImageProducer Objekt, keinImage Objekt.

Die Methoden getResource und getResourceAsStream suchen eine Ressource mit einem bestimmten Namen. Sie geben null zurück, wenn sie keine Ressource mit dem angegebenen Namen finden. Die Regeln für die Suche nach Ressourcen, die mit einer bestimmten Klasse assoziiert sind, werden durch den ClassLoader der Klasse implementiert. Die Class-Methoden delegieren anClassLoader-Methoden, nachdem sie eine Namenskonvention angewendet haben: Wenn der Ressourcenname mit „/“ beginnt, wird er so verwendet, wie er ist, andernfalls wird der Name des Pakets vorangestellt, nachdem alle Punkte (.) in Schrägstriche (/) umgewandelt wurden.

public InputStream getResourceAsStream(String name) { name = resolveName(name); ClassLoader cl = getClassLoader(); if (cl==null) { return ClassLoader.getSystemResourceAsStream(name); // A system class. } return cl.getResourceAsStream(name);}public java.net.URL getResource(String name) { name = resolveName(name); ClassLoader cl = getClassLoader(); if (cl==null) { return ClassLoader.getSystemResource(name); // A system class. } return cl.getResource(name);}

Die resolveName-Methode fügt einen Paketnamen-Präfix hinzu, wenn der Name nicht absolut ist, und entfernt jedes führende „/“, wenn der Name absolut ist. Es ist möglich, wenn auch unüblich, Klassen in verschiedenen Paketen zu haben, die sich dieselbe Ressource teilen.

private String resolveName(String name) { if (name == null) { return name; } if (!name.startsWith("/")) { Class c = this; while (c.isArray()) { c = c.getComponentType(); } String baseName = c.getName(); int index = baseName.lastIndexOf('.'); if (index != -1) { name = baseName.substring(0, index).replace('.', '/') + "/" + name; } } else { name = name.substring(1); } return name;}

Verwendung von Methoden von java.lang.ClassLoader

Die Klasse ClassLoader hat zwei Sätze von Methoden um auf Ressourcen zuzugreifen. Ein Satz gibt einen InputStream für die Ressource zurück. Der andere Satz gibt eine URL zurück. Die Methoden, die eine InputStream zurückgeben, sind einfacher zu verwenden und erfüllen viele Bedürfnisse, während die Methoden, die URLs zurückgeben, Zugriff auf komplexere Informationen bieten, wie z. B. ein Bild und einen Audio-Clip.

Die ClassLoaderverändert Ressourcen ähnlich wie die Art und Weise, wie sie Klassen verwaltet. Ein ClassLoader steuert, wie der Name einer Ressource auf ihren Inhalt abgebildet wird. ClassLoader bietet auch Methoden für den Zugriff auf Systemressourcen, analog zu den Systemklassen. Die ClassKlasse bietet einige Komfortmethoden, die die Funktionalität an die ClassLoaderMethoden delegieren.

Viele Java-Programme werden auf diese Methoden indirekt über die I18N (Lokalisierung) APIs zugreifen. Andere werden über Methoden in Class darauf zugreifen. Einige wenige werden die Methoden in ClassLoader direkt aufrufen.

Die Methoden in ClassLoader verwenden die angegebene Zeichenkette als Namen der Ressource, ohne eine absolute/relative Umwandlung vorzunehmen (siehe die Methoden in Class). Der Name sollte kein führendes „/“ haben.

Systemressourcen sind solche, die direkt von der Hostimplementierung gehandhabt werden. Sie können sich zum Beispiel imCLASSPATH befinden.

Der Name einer Ressource ist eine „/“-getrennte Folge von Bezeichnern. Die Klasse Class bietet Convenience-Methoden für den Zugriff auf Ressourcen; die Methoden implementieren eine Konvention, bei der der Paketname dem Kurznamen der Ressource vorangestellt wird.

Auf Ressourcen kann als InputStream oder als URL zugegriffen werden.

Die Methode getSystemResourceAsStream gibt einen InputStream für die angegebene Systemressource zurück oder null, wenn sie die Ressource nicht findet. Der Ressourcenname kann eine beliebige Systemressource sein.

Die Methode getSystemResource findet eine Systemressource mit dem angegebenen Namen. Sie gibt eine URL zur Ressource oder null zurück, wenn sie die Ressource nicht findet. Der Aufruf vonjava.net.URL.getContent() mit der URL gibt ein Objekt wie ImageProducer, AudioClip oder InputStream zurück.

Die Methode getResourceAsStream gibt einInputStream für die angegebene Ressource zurück oder null, wenn sie die Ressource nicht findet.

Die Methode getResource findet eine Ressource mit dem angegebenen Namen. Sie gibt eine URL zur Ressource zurück oder null, wenn sie die Ressource nicht findet. Der Aufruf von java.net.URL.getContent() mit der URL gibt ein Objekt wie ImageProducer, AudioClip oder InputStream zurück.

Sicherheit

Da getResource() den Zugriff auf Informationen ermöglicht, muss es wohldefinierte und fundierte Sicherheitsregeln haben. Wenn Sicherheitserwägungen es nicht zulassen, dass eine Ressource in einem Sicherheitskontext sichtbar ist, wird die getResource()-Methode fehlschlagen (null zurückgeben), als ob die Ressource überhaupt nicht vorhanden wäre, was Existenzangriffe adressiert.

Klassenlader dürfen aus Sicherheits- und Leistungsgründen keinen Zugriff auf den Inhalt einer .class-Datei gewähren. Ob es möglich ist, eine URL für eine .class-Datei zu erhalten, hängt von den Besonderheiten ab, wie unten gezeigt wird.

Es gibt keine spezifizierten Sicherheitsprobleme oder Einschränkungen in Bezug auf Ressourcen, die von einem Nicht-System-Klassenlader gefunden werden.AppletClassLoader bietet Zugriff auf Informationen, die von einem Quellort geladen werden, entweder einzeln oder in einer Gruppe durch eine JAR-Datei; daher sollte AppletClassLoaderdie gleichen checkConnect()Regeln beim Umgang mit URLs durch getResource() anwenden.

Das System ClassLoader bietet Zugriff auf Informationen im CLASSPATH. Ein CLASSPATH kann Verzeichnisse und JAR-Dateien enthalten. Da eine JAR-Datei absichtlich erstellt wird, hat sie eine andere Bedeutung als ein Verzeichnis, in dem die Dinge eher zufällig landen können. Insbesondere sind wir strenger, wenn es darum geht, Informationen aus einem Verzeichnis zu erhalten, als aus einer JAR-Datei.

Wenn sich eine Ressource in einem Verzeichnis befindet:

  • getResource() Aufrufe verwendenFile.exists(), um zu bestimmen, ob die entsprechende Datei für den Benutzer sichtbar gemacht werden soll. Erinnern Sie sich, dassFile.exists() die checkRead()-Methode im Sicherheitsmanager verwendet.
  • Das Gleiche gilt für getResourceAsStream().

Wenn sich die Ressource in einer JAR-Datei befindet:

  • getResource()Aufrufe werden für alle Dateien erfolgreich sein, unabhängig davon, ob der Aufruf aus einer System- oder einer Nicht-System-Klasse erfolgt.
  • getResourceAsStream()Aufrufe werden für Nicht-.class-Ressourcen erfolgreich sein, ebenso wie fürjava.net.URL.getContent() auf entsprechenden URLs.

Beispiele

Dieser Abschnitt enthält zwei Beispiele für Client-Code. Das erste Beispiel verwendet „absolute Ressourcennamen“ und traditionelle Mechanismen, um ein Class Objekt zu erhalten.

package pkg;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;class Test { private static final String absName = "/pkg/mumble.baf"; public static void test1() { Class c=null; try { c = Class.forName("pkg.Test"); } catch (Exception ex) { // This should not happen. } InputStream s = c.getResourceAsStream(absName); // do something with it. } public void test2() { InputStream s = this.getClass().getResourceAsStream(absName); // do something with it. }}

Dieses Beispiel verwendet „relative Ressourcennamen“ und den vom Compiler über das -experimentalFlag verfügbaren Mechanismus, um ein Class Objekt zu erhalten.

package pkg;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;class Test { private static final String relName = "mumble.baf"; public static void test1() { InputStream s = Test.class.getResourceAsStream(relName); // do something with it.} public void test2() { InputStream s = Test.class.getResourceAsStream(relName); // do something with it. }

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.