Přístup ke zdrojům nezávislý na umístění
- Přehled
- Zdroje, jména a kontexty
- Systémové zdroje
- Nesystémové zdroje
- Jména zdrojů
- Použití metod java.lang.Class
- Použití metodjava.lang.ClassLoader
- Zabezpečení
- Příklady
Přehled
Zdroj jsou data (obrázky, zvuky, text apod.), ke kterým potřebuje program přistupovat způsobem, který je nezávislý na umístění programového kódu. Programy v jazyce Java mohou používat dva mechanismypro přístup ke zdrojům: Aplety používají Applet.getCodeBase()
pro získání základní adresy URL pro kód appletu a poté rozšíří základní adresuURL o relativní cestu pro načtení požadovaného zdroje, například pomocí Applet.getAudioClip(url)
. Aplikace používají „dobře známá umístění“, napříkladSystem.getProperty("user.home")
neboSystem.getProperty("java.home")
, pak přidají“/lib/resource“ a otevřou tento soubor.
Metody ve třídách Class
aClassLoader
poskytují způsob umístění zdrojů nezávislý na umístění. Umožňují například lokalizovat zdroje pro:
- Applet načtený z Internetu pomocí vícenásobného připojení HTTP.
- Applet načtený pomocí souborů JAR.
- Java Bean načtený nebo nainstalovaný v CLASSPATH.
- „Knihovna“ nainstalovaná v CLASSPATH.
Tyto metody neposkytují specifickou podporu pro lokalizaci lokalizovaných zdrojů. Lokalizované zdroje jsou podporoványinternacionalizačními prostředky.
Zdroje, názvy a kontexty
Zdroj je identifikován řetězcem složeným z posloupnosti podřetězců oddělených lomítky (/), za kterým následuje název zdroje.Každý podřetězec musí být platným identifikátorem jazyka Java. Název prostředku má tvar shortName
neboshortName.extension
. JakshortName
, tak extension
musí být identifikátory jazyka Java.
Název prostředku je nezávislý na implementaci jazyka Java; zejména oddělovač cesty je vždy lomítko(/). Implementace Java však řídí podrobnosti toho, jakje obsah prostředku mapován do souboru, databáze nebo jiného objektu obsahujícího skutečný prostředek.
Interpretace názvu prostředku je relativní vůči instanci classloaderu. Tuto interpretaci provádějí metody implementované třídouClassLoader
.
Systémové prostředky
Systémový prostředek je prostředek, který je buď vestavěný v systému, nebo je uchováván implementací hostitele například v lokálním souborovém systému. Programy přistupují k systémovým zdrojům prostřednictvím metodClassLoader
getSystemResource
agetSystemResourceAsStream
.
Například v konkrétní implementaci může vyhledání systémového zdroje zahrnovat prohledávání záznamů v CLASSPATH. MetodyClassLoader
prohledají každý adresář, soubor ZIP nebo položku souboru JAR v CLASSPATH pro soubor zdroje, a pokud jej najdou, vrátí buď InputStream
, nebo název zdroje. Pokud není nalezen, metody vrátí null. Zdroj může být nalezen v jiné položce v CLASSPATH, než je umístění, kde byl soubor třídy načten.
Nesystémové zdroje
Implementace getResource
při načítání třídy závisí na podrobnostech třídy ClassLoader
. Například AppletClassLoader
:
- Nejprve se pokusí najít prostředek jako systémový prostředek; potom,pokud není nalezen,
- Prohledá prostředky v archivech (souborech JAR) již nahraných v této databázi CODEBASE; potom, pokud není nalezen,
- Použije databázi CODEBASE a pokusí se prostředek najít (což můževyžadovat kontaktování vzdálené stránky).
Všechny zavaděče tříd vyhledají prostředek nejprve jako systémovýzdroj, a to způsobem analogickým k vyhledávání souborů tříd. Toto pravidlo vyhledávání umožňuje přepsat lokálně jakýkoli prostředek. Klienti by měli zvolit název prostředku, který bude jedinečný (například pomocí názvu společnosti nebo balíčku jako předpony).
Název prostředku
Obvyklá konvence pro název prostředku používaného třídou je použít plně kvalifikovaný název balíčku třídy, ale převést všechny tečky (.) na lomítka (/) a přidat název prostředku ve tvaru name.extension
. Pro podporu tohoto a pro zjednodušení manipulace s detaily systémových tříd (pro kterégetClassLoader
vrací null) poskytuje třídaClass
dvě komfortní metody, které volají příslušné metody v ClassLoader
.
Název prostředku zadaný metodě Class
může mít počáteční počáteční „/“, které jej identifikuje jako „absolutní“ název.Názvy zdrojů, které nezačínají znakem „/“, jsou „relativní“.
Absolutní názvy jsou zbaveny počátečního znaku „/“ a jsou bez dalších úprav předány příslušné metoděClassLoader
pro vyhledání zdroje. Relativní názvy jsou upraveny podle dříve popsané konvencea poté jsou předány metodě ClassLoader
.
Použití metod třídy java.lang.Class
Třída Class
implementuje několik metod pro načítání zdrojů.
Metoda getResource()
vrací URL pro danýzdroj. Adresa URL (a její reprezentace) je specifická proimplementaci a JVM (to znamená, že adresa URL získaná v jedné instanci nemusí fungovat v jiné). Jeho protokol je obvykle specifický pro ClassLoader
načítání zdroje. Pokud prostředek neexistuje nebo není viditelný z bezpečnostních důvodů, metody vracejí nulu.
Pokud chce klientský kód načíst obsah prostředku jako InputStream
, může na URL použít metoduopenStream()
. To je dostatečně běžné, aby to ospravedlnilo přidání getResourceAsStream()
kClass
a ClassLoader
. getResourceAsStream()
je stejné jako volánígetResource().openStream()
, s tím rozdílem, žegetResourceAsStream()
zachycuje výjimky IO a vrací nulovou InputStream
.
Klientský kód může také požadovat obsah prostředku jako objekt použitím metody java.net.URL.getContent()
na URL. To je užitečné, pokud zdroj obsahuje například data pro obrázek. V případě obrázku je výsledkem objekt awt.image.ImageProducer
, nikoli objektImage
.
Metody getResource
agetResourceAsStream
vyhledají prostředek s daným názvem. Pokud nenajdou prostředek se zadaným názvem, vrátí null. Pravidla pro vyhledávání zdrojůspojených s danou třídou jsou implementována pomocíClassLoader třídy. Metody Class
delegují metodyClassLoader
po použití jmenné konvence: pokud jméno zdroje začíná znakem „/“, použije se tak, jak je, v opačném případě se přidá předpona názvu balíku po převedení všech teček (.) na lomítka (/).
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);}
Metoda resolveName
přidá předponu názvu balíku, pokud název není absolutní, a odstraní všechny úvodní znaky „/“, pokud je název absolutní. Je možné, i když neobvyklé, aby třídyv různých balíčcích sdílely stejný prostředek.
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;}
Použití metod java.lang.ClassLoader
Třída ClassLoader
má dvě sady metod propřístup ke zdrojům. Jedna sada vrací InputStream
zdroj. Druhá sada vrací adresu URL. Metody, které vracejí InputStream
, se používají snadněji a uspokojí mnohopotřeb, zatímco metody, které vracejí URL, umožňují přístup ke složitějším informacím, jako je obrázek a zvukový klip.
Třída ClassLoader
změňuje zdroje podobně jako způsob správy tříd. A ClassLoader
řídí způsob přiřazení názvu prostředku k jeho obsahu. ClassLoader
Také poskytuje metody pro přístup k systémovým prostředkům,analogicky k systémovým třídám. Třída Class
poskytuje některé komfortní metody, které delegují funkčnost na metody ClassLoader
.
Mnoho programů v Javě bude k těmto metodám přistupovat nepřímo prostřednictvím rozhraní I18N (lokalizace) API. Jiné k nim budou přistupovat prostřednictvím metodv Class
. Několik z nich bude metody v ClassLoader
volat přímo.
Metody v ClassLoader
používají zadaný řetězec jako název zdroje bez použití absolutní/relativní transformace (viz metody ve třídě). Název by neměl mít počáteční „/“.
Systémové prostředky jsou ty, které jsou zpracovávány přímo hostitelskou implementací. Mohou být například umístěny vCLASSPATH.
Název prostředku je posloupnost identifikátorů oddělená znakem „/“. Třída Class
poskytuje komfortnímetody pro přístup ke zdrojům; metody implementují konvenci, kdy je název balíku předřazen krátkému názvu zdroje.
Ke zdrojům lze přistupovat jako k InputStream
, nebo jako kURL.
Metoda getSystemResourceAsStream
vracíInputStream pro zadaný systémový zdroj nebo null, pokud zdroj nenajde. Název prostředku může být libovolný systémový prostředek.
Metoda getSystemResource
najde systémový prostředek se zadaným názvem. Vrátí adresu URL na daný prostředeknebo null, pokud prostředek nenajde. Voláníjava.net.URL.getContent()
s URL vrátí objekt, například ImageProducer
, AudioClip
nebo InputStream
.
Metoda getResourceAsStream
vrátíInputStream
pro zadaný prostředek nebo null, pokud prostředek nenajde.
Metoda getResource
najde prostředek se zadaným názvem. Vrátí adresu URL daného prostředku nebo null, pokud daný prostředek nenajde. Voláníjava.net.URL.getContent()
s URL vrátí objekt, například ImageProducer
, AudioClip
nebo InputStream
.
Zabezpečení
Protože getResource()
poskytuje přístup k informacím,musí mít dobře definovaná a podložená bezpečnostní pravidla. Pokudbezpečnostní hlediska neumožňují, aby byl prostředek viditelný vněkterém bezpečnostním kontextu, metoda getResource()
selže (vrátí null), jako by prostředek vůbec nebyl přítomen, což řeší existenční útoky.
Zavaděče tříd nesmí z bezpečnostních i výkonnostních důvodů poskytovat přístup k obsahu souboru třídy. To, zda jemožné získat adresu URL souboru třídy .class, závisí na specifikách, jak je uvedeno níže.
Nejsou specifikovány žádné bezpečnostní problémy nebo omezení týkající sezdrojů, které jsou nalezeny nesystémovým zavaděčem tříd.AppletClassLoader
Poskytuje přístup k informacím, které jsou načteny ze zdrojového umístění, a to buď jednotlivě, nebo ve skupině prostřednictvím souboru JAR; proto by AppletClassLoader
měl použít stejná pravidla checkConnect()
při práci s URL prostřednictvím getResource()
.
Systém ClassLoader
poskytuje přístup k informacím v CLASSPATH. CLASSPATH může obsahovat adresářea soubory JAR. Vzhledem k tomu, že soubor JAR je vytvářen záměrně, májiný význam než adresář, ve kterém mohou věci skončitnáhodněji. Zejména jsme přísnější na získávání informací z adresáře než ze souboru JAR.
Pokud je zdroj v adresáři:
-
getResource()
vyvolání použijeFile.exists()
k určení, zda má být příslušný soubor viditelný pro uživatele. Připomeňme, žeFile.exists()
používá metoducheckRead()
ve správci zabezpečení. - totéž platí pro
getResourceAsStream()
.
Je-li prostředek v souboru JAR:
-
getResource()
vyvolání bude úspěšné pro všechny soubory bez ohledu na to, zda je vyvolání provedeno ze systémové nebo nesystémové třídy. -
getResourceAsStream()
vyvolání budou úspěšná pro prostředky, které nejsou ve třídě .class, a stejně tak projava.net.URL.getContent()
na odpovídajících adresách URL.
Příklady
Tato část obsahuje dva příklady klientského kódu. První příklad používá „absolutní názvy prostředků“ a tradiční mechanismus pro získání objektu Class
.
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. }}
Tento příklad používá „relativní názvy prostředků“ a mechanismus dostupný z překladače prostřednictvím příznaku -experimental
, pro získání objektu Class
.
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. }
.