Locatie-onafhankelijke toegang tot bronnen
- Overzicht
- Bronnen, namen en contexten
- Systeembronnen
- Niet-systeembronnen
- Bronnennamen
- Methoden gebruiken van java.lang.Class
- Methoden van java.lang.ClassLoader
- Veiligheid
- Voorbeelden
Overzicht
Een resource is data (afbeeldingen, audio, tekst, enzovoort) waar een programma toegang toe moet krijgen op een manier die onafhankelijk is van de locatie van de programmacode. Java-programma’s kunnen twee mechanismen gebruiken om toegang te krijgen tot bronnen: Applets gebruiken Applet.getCodeBase()
om de basisURL voor de applet-code te krijgen en breiden dan de basisURL uit met een relatief pad om de gewenste bron te laden, bijvoorbeeld met Applet.getAudioClip(url)
. Applicaties gebruiken “bekende locaties” zoalsSystem.getProperty("user.home")
ofSystem.getProperty("java.home")
, voegen dan “/lib/resource” toe, en openen dat bestand.
Methods in de klassen Class
enClassLoader
bieden een locatie-onafhankelijke manier om bronnen te lokaliseren. Ze maken bijvoorbeeld het lokaliseren van bronnen mogelijk voor:
- Een applet geladen van het Internet met behulp van meerdere HTTP-connecties.
- Een applet geladen met behulp van JAR-bestanden.
- Een Java Bean geladen of geïnstalleerd in het CLASSPATH.
- Een “library” geïnstalleerd in het CLASSPATH.
Deze methoden bieden geen specifieke ondersteuning voor het lokaliseren van gelokaliseerde bronnen. Gelokaliseerde bronnen worden ondersteund door de internationaliseringsfaciliteiten.
Bronnen, namen en contexten
Een bron wordt geïdentificeerd door een tekenreeks die bestaat uit een opeenvolging van subtekenreeksen, begrensd door schuine strepen (/), gevolgd door een bronnaam.Elke subtekenreeks moet een geldige Java-identifier zijn. De naam van de bron is van de vorm shortName
ofshortName.extension
. ZowelshortName
als extension
moeten Java identifiers zijn.
De naam van een resource is onafhankelijk van de Java-implementatie; in het bijzonder, het pad scheidingsteken is altijd een schuine streep (/). De Java-implementatie bepaalt echter in detail hoe de inhoud van de resource wordt toegewezen aan een bestand, een database of een ander object dat de eigenlijke resource bevat.
De interpretatie van een resource-naam is relatief ten opzichte van een instantie van de classloader. Methoden die zijn geïmplementeerd door de klasse ClassLoader
doen deze interpretatie.
Systeemhulpbronnen
Een systeemhulpbron is een hulpbron die ofwel is ingebouwd in het systeem, of wordt bewaard door de host-implementatie in, bijvoorbeeld, een lokaal bestandssysteem. Programma’s hebben toegang tot systeembronnen via deClassLoader
methoden getSystemResource
engetSystemResourceAsStream
.
In een bepaalde implementatie kan het lokaliseren van een systeembron bijvoorbeeld bestaan uit het doorzoeken van de ingangen in het CLASSPATH. DeClassLoader
methoden zoeken in elke directory, ZIP-bestand, of JAR-bestand in het CLASSPATH naar het bronbestand, en, indien gevonden, retourneert het ofwel een InputStream
, of de bronnaam. Indien niet gevonden, retourneert de methode null. Een resource kan worden gevonden in een andere entry in het CLASSPATH dan de locatie waar het klasse-bestand werd geladen.
Niet-Systeem Hulpbronnen
De implementatie van getResource
op een geladen klasse hangt af van de details van de ClassLoader
klasse. Bijvoorbeeld, AppletClassLoader
:
- Probeert eerst de bron als een systeembron te vinden; dan, indien niet gevonden,
- zoekt de bronnen in archieven (JAR-bestanden) die reeds in deze CODEBASE zijn geladen; dan, indien niet gevonden,
- Gebruikt CODEBASE en probeert de bron te vinden (wat kan inhouden dat contact wordt opgenomen met een externe site).
Alle klasse-loaders zullen een bron eerst als systeembron zoeken, op een wijze die analoog is aan het zoeken naar klasse-bestanden. Deze zoekregel staat het lokaal overschrijven van elke resource toe. Clients moeten een unieke naam voor de resource kiezen (bijvoorbeeld door de bedrijfs- of pakketnaam als prefix te gebruiken).
Resource Namen
Een gebruikelijke conventie voor de naam van een door een klasse gebruikte resource is om de volledig gekwalificeerde naam van het pakket van de klasse te gebruiken, maar alle punten (.) om te zetten in schuine strepen (/), en een resource naam van de vorm name.extension
toe te voegen. Om dit te ondersteunen, en om de afhandeling van de details van systeemklassen (waarvoorgetClassLoader
null retourneert) te vereenvoudigen, verschaft de klasseClass
twee gemaksmethoden die de juiste methoden in ClassLoader
aanroepen.
De bronnaam die aan een Class
methode wordt gegeven kan een beginnend “/” hebben dat het identificeert als een “absolute” naam.Resourcenamen die niet met een “/” beginnen, zijn “relatief”.
Absolute namen worden ontdaan van hun initiaal “/” en zonder verdere wijziging doorgegeven aan de juiste methode ClassLoader
om de bron te lokaliseren. Relativenamen worden gewijzigd volgens de eerder beschreven conventie en worden dan doorgegeven aan een ClassLoader
methode.
Methoden van java.lang.Class
De Class
klasse implementeert verschillende methoden voor het laden van bronnen.
De methode getResource()
retourneert een URL voor de bron. De URL (en de representatie ervan) is specifiek voor de implementatie en de JVM (dat wil zeggen, de URL verkregen in een andereuntime-instantie werkt mogelijk niet in een andere). Het protocol is gewoonlijk specifiek voor de ClassLoader
die de bron laadt. Als de bron niet bestaat of niet zichtbaar is vanwege veiligheidsoverwegingen, retourneert de methode null.
Als de client code de inhoud van de bron wil lezen als een InputStream
, kan het deopenStream()
methode toepassen op de URL. Dit is gebruikelijk genoeg om getResourceAsStream()
toe te voegen aanClass
en ClassLoader
.getResourceAsStream()
is hetzelfde als het aanroepen vangetResource().openStream()
, behalve datgetResourceAsStream()
IO excepties opvangt en een InputStream
teruggeeft.
Client code kan ook de inhoud van de bron opvragen als een object door de java.net.URL.getContent()
methode op de URL toe te passen. Dit is nuttig wanneer de resource bijvoorbeeld de gegevens van een afbeelding bevat. In het geval van een afbeelding is het resultaat een awt.image.ImageProducer
-object, niet eenImage
-object.
De methoden getResource
engetResourceAsStream
zoeken een resource met een gegeven naam. Ze retourneren null als ze geen resource met de opgegeven naam vinden. De regels voor het zoeken naar resources die bij een bepaalde klasse horen, worden geïmplementeerd door deClassLoader van de klasse. De Class
methodes delegeren naarClassLoader
methodes, na het toepassen van een naamgevingsconventie: als de naam van de resource begint met “/”, wordt deze gebruikt zoals hij is. Anders wordt de naam van het package voorafgegaan, na het converteren van alle punten (.) naar schuine strepen (/).
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);}
De resolveName
methode voegt een package naam prefix toe als de naam niet absoluut is, en verwijdert elke voorloop “/” als de naam absoluut is. Het is mogelijk, hoewel ongebruikelijk, om klassen in verschillende pakketten te hebben die dezelfde bron delen.
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;}
Methoden van java.lang.ClassLoader
De ClassLoader
klasse heeft twee sets van methoden om toegang te krijgen tot bronnen. Een set retourneert een InputStream
voor de bron. De andere set retourneert een URL. De methodes die een InputStream
retourneren zijn gemakkelijker te gebruiken en zullen aan veel behoeften voldoen, terwijl de methodes die URLs retourneren toegang geven tot meer complexe informatie, zoals een Afbeelding en een AudioClip.
De ClassLoader
wijzigt bronnen op dezelfde manier als de manier waarop het klassen beheert. Een ClassLoader
regelt hoe de naam van een bron aan zijn inhoud moet worden gekoppeld. ClassLoader
verschaft ook methodes voor toegang tot systeembronnen, analoog aan de systeemklassen. De Class
klasse verschaft een aantal gemakkelijke methodes die functionaliteit delegeren naar de ClassLoader
methodes.
Vele Java programma’s zullen indirect toegang krijgen tot deze methodes via de I18N (lokalisatie) APIs. Anderen zullen er toegang toe krijgen via methodes in Class
. Enkelen zullen de ClassLoader
methoden direct aanroepen.
De methoden in ClassLoader
gebruiken de gegeven String als de naam van de bron zonder enige absolute/relatieve transformatie toe te passen (zie de methoden in Klasse). De naam mag niet worden voorafgegaan door een “/”.
Systeembronnen zijn bronnen die rechtstreeks door de hostimplementatie worden behandeld. Zij kunnen zich bijvoorbeeld in hetCLASSPATH bevinden.
De naam van een hulpbron is een “/”-gescheiden opeenvolging vanidentifiers. De klasse Class
biedt handige methoden voor toegang tot bronnen; de methoden implementeren een conventie waarbij de pakketnaam wordt voorafgegaan door de korte naam van de bron.
Bronnen kunnen worden benaderd als een InputStream
, of eenURL.
De methode getSystemResourceAsStream
retourneert een InputStream voor de opgegeven systeembron of nul als de bron niet wordt gevonden. De naam van de bron kan elke systeembron zijn.
De methode getSystemResource
vindt een systeembron met de opgegeven naam. Zij retourneert een URL naar de bron of null als zij de bron niet vindt. Het aanroepen van java.net.URL.getContent()
met de URL zal een object zoals ImageProducer
, AudioClip
, of InputStream
teruggeven.
De methode getResourceAsStream
retourneert eenInputStream
voor de gespecificeerde resource of null als de resource niet wordt gevonden.
De methode getResource
vindt een resource met de gespecificeerde naam. Het retourneert een URL naar de bron of null als de bron niet wordt gevonden. Het aanroepen vanjava.net.URL.getContent()
met de URL zal een object zoals ImageProducer
, AudioClip
, of InputStream
teruggeven.
Veiligheid
Omdat getResource()
toegang tot informatie verschaft, moet het goed gedefinieerde en gefundeerde veiligheidsregels hebben. Als veiligheidsoverwegingen niet toestaan dat een bron zichtbaar is in een of andere veiligheidscontext, zal de methode getResource()
falen (nul teruggeven) alsof de bron helemaal niet aanwezig is, dit adresseert bestaansaanvallen.
Class loaders mogen geen toegang geven tot de inhoud van een .classfile om zowel veiligheids- als prestatieredenen. Of het mogelijk is om een URL voor een .class-bestand te verkrijgen, hangt af van de specifieke kenmerken, zoals hieronder weergegeven.
Er zijn geen gespecificeerde veiligheidskwesties of beperkingen met betrekking tot bronnen die worden gevonden door een niet-systeem class loader.AppletClassLoader
verschaft toegang tot informatie die is geladen vanaf een bronlocatie, hetzij individueel, hetzij in een groep via een JAR-bestand; dus AppletClassLoader
dient dezelfde checkConnect()
-regels toe te passen bij het omgaan met URL’s via getResource()
.
Het systeem ClassLoader
verschaft toegang tot informatie in het CLASSPATH. Een CLASSPATH kan directories en JAR bestanden bevatten. Aangezien een JAR bestand opzettelijk wordt aangemaakt, heeft het een andere betekenis dan een directory waar dingen op een meer toevallige manier in terecht kunnen komen. In het bijzonder zijn we strenger in het verkrijgen van informatie uit een directory dan uit een JAR bestand.
Als een bron in een directory staat:
-
getResource()
invocaties zullenFile.exists()
gebruiken om te bepalen of het corresponderende bestand zichtbaar moet worden gemaakt voor de gebruiker. Onthoud datFile.exists()
de methodecheckRead()
in de beveiligingsmanager gebruikt. - hetzelfde geldt voor
getResourceAsStream()
.
Als de bron zich in een JAR-bestand bevindt:
-
getResource()
aanroepen zullen slagen voor alle bestanden, ongeacht of de aanroep wordt gedaan vanuit een systeem of een niet-systeemklasse. -
getResourceAsStream()
aanroepingen zullen slagen voor niet .class bronnen, en zo ook voorjava.net.URL.getContent()
op overeenkomstige URLs.
Voorbeelden
Deze sectie geeft twee voorbeelden van client code. Het eerste voorbeeld gebruikt “absolute bron”-namen en traditionele mechanismen om een Class
object te krijgen.
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. }}
Dit voorbeeld gebruikt “relatieve bron”-namen en het mechanisme dat beschikbaar is via de -experimental
flag van de compiler, om een Class
object te krijgen.
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. }