Accesul la resurse independent de locație
- Vizualizare
- Resurse, nume și contexte
- Resurse de sistem
- Resurse nesistemice
- Numele resurselor
- Numele resurselor
- Utilizarea metodelor din java.lang.Class
- Utilizarea metodelor din java.lang.ClassLoader
- Securitate
- Exemple
Overview
Orice resursă reprezintă date (imagini, audio, text etc.) pe care un program trebuie să le acceseze într-un mod independent de locația codului programului. Programele Java pot folosi două mecanismepentru a accesa resursele: Applet-urile folosesc Applet.getCodeBase()
pentru a obține URL-ul de bază pentru codul applet-ului și apoi extind URL-ul de bază cu o cale relativă pentru a încărca resursa dorită, de exemplu cu Applet.getAudioClip(url)
. Aplicațiile folosesc „locații bine cunoscute”, cum ar fiSystem.getProperty("user.home")
sauSystem.getProperty("java.home")
, apoi adaugă „/lib/resource” și deschid acel fișier.
Metodele din clasele Class
șiClassLoader
oferă o modalitate independentă de locație de a localiza resursele. De exemplu, acestea permit localizarea resurselorpentru:
- Un applet încărcat de pe Internet folosind mai multe conexiuni HTTP.
- Un applet încărcat folosind fișiere JAR.
- Un Java Bean încărcat sau instalat în CLASSPATH.
- O „bibliotecă” instalată în CLASSPATH.
Aceste metode nu oferă suport specific pentru localizarea resurselor localizate. Resursele localizate sunt susținute de facilitățile de internaționalizare.
Resurse, nume și contexte
O resursă este identificată printr-un șir de caractere format dintr-o secvență de subșiruri, delimitate prin bară oblică (/), urmată de un nume de resursă.Fiecare subșir trebuie să fie un identificator Java valid. Numele resursei este de forma shortName
saushortName.extension
. Atât shortName
, cât și extension
trebuie să fie identificatori Java.
Numele unei resurse este independent de implementarea Java; în special, separatorul de cale este întotdeauna o bară oblică (/). Cu toate acestea, implementarea Java controlează detaliile privind modul în care conținutul resursei este mapat într-un fișier, bază de date sau alt obiect care conține resursa reală.
Interpretarea numelui unei resurse este relativă la o instanță de încărcător de clasă. Metodele implementate de clasaClassLoader
fac această interpretare.
Resurse de sistem
O resursă de sistem este o resursă care este fie încorporată în sistem, fie păstrată de către implementarea gazdă în, de exemplu, un sistem de fișiere local. Programele accesează resursele de sistem prin intermediul metodelorClassLoader
getSystemResource
șigetSystemResourceAsStream
.
De exemplu, într-o anumită implementare, localizarea unei resurse de sistem poate implica căutarea intrărilor din CLASSPATH. MetodeleClassLoader
caută în fiecare director, fișier ZIP sau intrare de fișier JAR din CLASSPATH pentru fișierul resursă și, dacă este găsit, returnează fie un InputStream
, fie numele resursei. Dacă nu sunt găsite, metodele returnează null. O resursă poate fi găsită într-o altă intrare din CLASSPATH decât locația în care a fost încărcat fișierul de clasă.
Resurse nesistemice
Implementarea lui getResource
la o clasă încărcată depinde de detaliile clasei ClassLoader
. De exemplu, AppletClassLoader
:
- Încercă mai întâi să localizeze resursa ca resursă de sistem; apoi,dacă nu este găsită,
- Cercetă printre resursele din arhivele (fișiere JAR) deja încărcate în acest CODEBASE; apoi, dacă nu este găsită,
- Utilizează CODEBASE și încearcă să localizeze resursa (ceea ce poateimplica contactarea unui site la distanță).
Toate încărcătoarele de clase vor căuta o resursă mai întâi ca resursă de sistem, într-o manieră analogă căutării fișierelor de clasă. Această regulă de căutare permite suprascrierea la nivel local a oricărei resurse. Clienții ar trebui să aleagă un nume de resursă care să fie unic (folosind numele companiei sau al pachetului ca prefix, de exemplu).
Numele resurselor
O convenție obișnuită pentru numele unei resurse folosite de o clasă este de a folosi numele complet calificat al pachetului clasei, dar de a converti toate punctele (.) în slash-uri (/) și de a adăuga un nume de resursă de forma name.extension
. Pentru a sprijini acest lucru și pentru a simplifica manipularea detaliilor claselor de sistem (pentru caregetClassLoader
returnează null), clasaClass
oferă două metode de conveniență care apelează metodele corespunzătoare din ClassLoader
.
Numele de resursă dat unei metode Class
poate avea un „/” inițial care începe cu „/” și care îl identifică ca fiind un nume „absolut”.Numele de resurse care nu încep cu un „/” sunt „relative”.
Numele absolute sunt lipsite de „/” inițial și sunt transmise, fără nicio altă modificare, metodei corespunzătoareClassLoader
pentru a localiza resursa. Numele relative sunt modificate în conformitate cu convenția descrisă anteriorși apoi sunt trecute la o metodă ClassLoader
.
Utilizarea metodelor din java.lang.Class
Clasa Class
implementează mai multe metode pentru încărcarea resurselor.
Metoda getResource()
returnează un URL pentru resursă. URL-ul (și reprezentarea sa) este specificimplementației și JVM-ului (adică, URL-ul obținut într-o instanță de uneruntime poate să nu funcționeze în alta). Protocolul său este de obicei specific pentru ClassLoader
care încarcă resursa. În cazul în care resursa nu există sau nu este vizibilă din considerente de securitate, metodele returnează null.
Dacă codul client dorește să citească conținutul resursei ca un InputStream
, poate aplica metodaopenStream()
asupra URL-ului. Acest lucru este suficient de comunpentru a justifica adăugarea getResourceAsStream()
laClass
și ClassLoader
.getResourceAsStream()
la fel ca și apelareagetResource().openStream()
, cu excepția faptului căgetResourceAsStream()
prinde excepțiile IO și returnează un InputStream
nul.
Codul client poate, de asemenea, să solicite conținutul resursei ca un obiect prin aplicarea metodei java.net.URL.getContent()
asupra URL-ului. Acest lucru este util atunci când resursa conține datele unei imagini, de exemplu. În cazul unei imagini, rezultatul este un obiect awt.image.ImageProducer
, nu un obiectImage
.
Metodele getResource
șigetResourceAsStream
găsesc o resursă cu un nume dat. Ele returnează null dacă nu găsesc o resursă cu numele specificat. Regulile de căutare a resurselor asociate cu o anumită clasă sunt implementate de ClassLoader-ul clasei respective. Metodele Class
deleagă la metodeleClassLoader
, după aplicarea unei convenții de denumire: dacă numele resursei începe cu „/”, acesta este utilizat ca atare.În caz contrar, se adaugă numele pachetului, după convertirea tuturor punctelor (.) în bară oblică (/).
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
adaugă un prefix pentru numele pachetului dacă numele nu este absolut și elimină orice „/” de început dacă numele este absolut. Este posibil, deși neobișnuit, ca clasele din pachete diferite să împartă aceeași resursă.
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;}
Utilizarea metodelor din java.lang.ClassLoader
Clasa ClassLoader
are două seturi de metode de accesare a resurselor. Un set returnează un InputStream
pentru resursă. Celălalt set returnează un URL. Metodele care returnează un InputStream
sunt mai ușor de utilizat și vor satisface multe nevoi, în timp ce metodele care returnează URL-uri oferă acces la informații mai complexe, cum ar fi o Imagine și un AudioClip.
Cea ClassLoader
gestionează resursele în mod similar cu modul în care gestionează clasele. Un ClassLoader
controlează modul în care se adaptează numele unei resurse la conținutul său. ClassLoader
oferă, de asemenea, metode de accesare a resurselor de sistem,analoage cu clasele de sistem. Clasa Class
oferă unele metode de conveniență care deleagă funcționalitatea metodelor ClassLoader
.
Multe programe Java vor accesa aceste metode indirect prin intermediul API-urilor I18N (localizare). Altele le vor accesa prin metodele din Class
. Câteva vor invoca direct metodeleClassLoader
.
Metodele din ClassLoader
utilizează șirul de caractere dat ca nume al resursei fără a aplica nicio transformare absolută/relativă (a se vedea metodele din Class). Numele nu trebuie să aibă un „/” de frunte.
Resursele de sistem sunt cele care sunt gestionate direct de către implementarea hostimplement. De exemplu, ele pot fi localizate înCLASSPATH.
Numele unei resurse este o secvență de identificatori separați de „/”. Clasa Class
oferă metode convenabile de accesare a resurselor; metodele implementează o convenție în care numele pachetului este prefixat la numele scurt al resursei.
Resursele pot fi accesate ca un InputStream
, sau ca unURL.
Metoda getSystemResourceAsStream
returnează unInputStream pentru resursa de sistem specificată sau null dacă nu găsește resursa. Numele resursei poate fi orice resursă de sistem.
Metoda getSystemResource
găsește o resursă de sistem cu numele specificat. Aceasta returnează o adresă URL către resursăsau null dacă nu găsește resursa. Apelareajava.net.URL.getContent()
cu URL-ul va returna un obiect cum ar fi ImageProducer
, AudioClip
sau InputStream
.
Metoda getResourceAsStream
returnează unInputStream
pentru resursa specificată sau null dacă nu găsește resursa.
Metoda getResource
găsește o resursă cu numele specificat. Aceasta returnează un URL către resursă sau null dacă nu găsește resursa. Apelareajava.net.URL.getContent()
cu URL-ul va returna un obiect, cum ar fi ImageProducer
, AudioClip
sau InputStream
.
Securitate
Din moment ce getResource()
oferă acces la informații,trebuie să aibă reguli de securitate bine definite și bine fundamentate. Dacă considerente de securitate nu permit ca o resursă să fie vizibilă într-un anumit context de securitate, metoda getResource()
va eșua (returnează null) ca și cum resursa nu ar fi deloc prezentă, acest lucruadresează atacurile de existență.
Cărcătorii de clasă nu pot oferi acces la conținutul unui fișier .class din motive de securitate și de performanță. Posibilitatea de a obține o adresă URL pentru un fișier .class depinde de specificul acestuia, după cum se arată mai jos.
Nu există probleme sau restricții de securitate specificate în ceea ce priveșteresursele care sunt găsite de un încărcător de clasă nesistemic.AppletClassLoader
oferă acces la informații care sunt încărcate dintr-o locație sursă, fie individual, fie în grup prin intermediul unui fișier JAR; astfel, AppletClassLoader
ar trebui să aplice aceleași reguli checkConnect()
atunci când tratează cu URL-uri prin getResource()
.
Sistemul ClassLoader
oferă acces la informații din CLASSPATH. Un CLASSPATH poate conține directoareși fișiere JAR. Deoarece un fișier JAR este creat în mod intenționat, el are o semnificație diferită față de un director în care lucrurile pot ajunge într-un mod mai întâmplător. În special, suntem mai stricți în ceea ce privește obținerea de informații dintr-un director decât dintr-un fișier JAR.
Dacă o resursă se află într-un director:
-
getResource()
invocările vor folosiFile.exists()
pentru a determina dacă fișierul corespunzător trebuie să fie vizibil pentru utilizator. Reamintim căFile.exists()
utilizează metodacheckRead()
în managerul de securitate. - același lucru se aplică și la
getResourceAsStream()
.
Dacă resursa se află într-un fișier JAR:
-
getResource()
invocările vor reuși pentru toate fișierele, indiferent dacă invocarea se face din cadrul unei clase de sistem sau a unei clase nesistemice. -
getResourceAsStream()
invocările vor reuși pentru resursele care nu sunt de tip .class, la fel și pentrujava.net.URL.getContent()
pe URL-urile corespunzătoare.
Exemple
Această secțiune oferă două exemple de cod client. Primulexemplu folosește nume de „resursă absolută” și mecanisme tradiționalepentru a obține un obiect 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. }}
Acest exemplu folosește nume de „resursă relativă” și mecanismuldisponibil din compilator prin intermediul markerului -experimental
, pentru a obține un obiect 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. }
.