Sijoituspaikasta riippumaton resurssien käyttäminen
- Yleiskatsaus
- Resurssit, nimet ja kontekstit
- Järjestelmäresurssit
- Järjestelmään kuulumattomat resurssit
- Resurssien nimet
- Käyttämällä menetelmiä java.lang.Class
- Using Methods ofjava.lang.ClassLoader
- Security
- Examples
Overview
Resurssi on dataa (kuvia, ääntä, tekstiä ja niin edelleen), jota ohjelman on käytettävä tavalla, joka on riippumaton ohjelmakoodin sijainnista. Java-ohjelmat voivat käyttää kahta mekanismia resurssien käyttämiseen: Appletit käyttävät Applet.getCodeBase()
saadakseen applet-koodin perus-URL-osoitteen ja laajentaakseen sitten perus-URL-osoitetta suhteellisella polulla halutun resurssin lataamiseksi, esimerkiksi Applet.getAudioClip(url)
:llä. Sovellukset käyttävät ”tunnettuja sijainteja”, kutenSystem.getProperty("user.home")
taiSystem.getProperty("java.home")
, lisää sitten”/lib/resource” ja avaa kyseinen tiedosto.
Luokkien Class
ja ClassLoader
metodit tarjoavat sijainnista riippumattoman tavan etsiä resursseja. Ne mahdollistavat esimerkiksi resurssien paikantamisen:
- Internetistä useiden HTTP-yhteyksien avulla ladattu appletti.
- JAR-tiedostojen avulla ladattu appletti.
- Javapapu, joka on ladattu tai asennettu CLASSPATH:iin.
- ClasSPATH:iin asennettu ”kirjasto”.
Nämä metodit eivät tarjoa erityistä tukea lokalisoitujen resurssien paikantamiseen. Lokalisoituja resursseja tuetaan kansainvälistämistoiminnoilla.
Resurssit, nimet ja kontekstit
Resurssi yksilöidään merkkijonolla, joka koostuu sarjasta alimerkkijonoja, jotka on erotettu vinoviivoilla (/) ja joita seuraa resurssin nimi.Jokaisen alimerkkijonon on oltava kelvollinen Java-tunniste. Resurssin nimi on muotoa shortName
tai shortName.extension
. SekäshortName
että extension
on oltava Java-tunniste.
Resurssin nimi on riippumaton Java-toteutuksesta; erityisesti polun erotin on aina vinoviiva(/). Java-toteutus hallitsee kuitenkin yksityiskohtia siitä, miten resurssin sisältö liitetään tiedostoon, tietokantaan tai muuhun varsinaista resurssia sisältävään objektiin.
Resurssin nimen tulkinta on suhteellinen luokanlatausinstanssiin nähden. LuokanClassLoader
toteuttamat metodit tekevät tämän tulkinnan.
Järjestelmäresurssit
Järjestelmäresurssi on resurssi, joka on joko sisäänrakennettu järjestelmään tai jota isäntätoteutus pitää esimerkiksi paikallisessa tiedostojärjestelmässä. Ohjelmat käyttävät järjestelmäresurssejaClassLoader
-metodien getSystemResource
ja getSystemResourceAsStream
kautta.
Jossain tietyssä toteutuksessa järjestelmäresurssin paikantaminen voi esimerkiksi edellyttää CLASSPATH:n merkintöjen etsimistä. MetoditClassLoader
etsivät CLASSPATHin jokaisen hakemiston, ZIP-tiedoston tai JAR-tiedoston merkinnän resurssitiedostosta, ja jos ne löytyvät, ne palauttavat joko InputStream
tai resurssin nimen. Jos tiedostoa ei löydy, metodit palauttavat nollan. Resurssi voi löytyä eri CLASSPATH-tietueesta kuin mistä luokkatiedosto ladattiin.
Ei järjestelmäresurssit
getResource
:n toteutus luokan latauksessa riippuu ClassLoader
-luokan yksityiskohdista. Esimerkiksi AppletClassLoader
:
- Yritetään ensin löytää resurssi järjestelmäresurssina; sitten,jos sitä ei löydy,
- Etsitään resursseja arkistoista (JAR-tiedostoista), jotka on jo ladattu tähän CODEBASEen; sitten,jos sitä ei löydy,
- Käytetään CODEBASEa ja yritetään löytää resurssi (mikä voi vaatia yhteydenottoa etäsivustoon).
Kaikki luokkien latausohjelmat etsivät resurssia ensin järjestelmäresurssina analogisesti luokkatiedostojen etsimiseen. Tämähakusääntö sallii minkä tahansa resurssin korvaamisen paikallisesti. Asiakkaiden tulisi valita resurssin nimi, joka on yksilöllinen (käyttämällä esimerkiksi yrityksen tai paketin nimeä etuliitteenä).
Resurssien nimet
Yleinen konventio luokan käyttämän resurssin nimelle on käyttää luokan paketin täysin pätevää nimeä, mutta muuttaa kaikki pisteet (.) vinoviivoiksi (/) ja lisätä resurssin nimi muotoa name.extension
. Tämän tukemiseksi ja yksinkertaistaakseen järjestelmäluokkien yksityiskohtien käsittelyä (joiden osaltagetClassLoader
palauttaa nollan), luokkaClass
tarjoaa kaksi mukavuusmetodia, jotka kutsuvat ClassLoader
:n sopivia metodeja.
Class
-metodille annetussa resurssinimessä voi olla alkuosana ”/”, joka identifioi sen ”absoluuttiseksi” nimeksi.Resurssinimet, jotka eivät ala ”/”-merkillä, ovat ”suhteellisia”.
Absoluuttisista nimistä poistetaan aloittava ”/”-merkki, ja ne välitetään ilman lisämuutoksia ClassLoader
-menetelmälle, joka etsii resurssin. Suhteellisia nimiä muokataan aiemmin kuvatun konvention mukaisesti ja välitetään sitten ClassLoader
-metodille.
Using Methods of java.lang.Class
Luokka Class
toteuttaa useita metodeja resurssien lataamista varten.
Metodi getResource()
palauttaa resurssin URL-osoitteen. URL-osoite (ja sen esitys) on riippuvainen toteutuksesta ja JVM:stä (toisin sanoen URL-osoite, joka on saatu eriaikaisessa instanssissa, ei välttämättä toimi toisessa instanssissa). Sen protokolla on yleensä resurssin lataavalle ClassLoader
:lle ominainen. Jos resurssia ei ole olemassa tai se ei ole näkyvissä turvallisuussyistä, metodit palauttavat nollan.
Jos asiakaskoodi haluaa lukea resurssin sisällön InputStream
:ksi, se voi soveltaa openStream()
-metodia URL-osoitteeseen. Tämä on niin yleistä, että getResourceAsStream()
:n lisääminenClass
:een ja ClassLoader
:een on perusteltua.getResourceAsStream()
on sama kuingetResource().openStream()
:n kutsuminen, paitsi että ottaa IO-poikkeukset kiinni ja palauttaa tyhjän InputStream
:n.
Asiakaskoodi voi myös pyytää resurssin sisällön objektina soveltamalla java.net.URL.getContent()
-metodia URL-osoitteeseen. Tämä on hyödyllistä, kun resurssi sisältää esimerkiksi kuvan tiedot. Kuvan tapauksessa tulos on awt.image.ImageProducer
-olio, eiImage
-olio.
getResource
– ja getResourceAsStream
-metodit etsivät resurssin, jolla on annettu nimi. Ne palauttavat nollan, jos ne eivät löydä resurssia annetulla nimellä. Säännöt tiettyyn luokkaan liittyvien resurssien etsimiseen on toteutettu luokanClassLoaderissa. Class
-metodit delegoivatClassLoader
-metodeille sen jälkeen, kun ne ovat soveltaneet nimeämiskonventiota: jos resurssin nimi alkaa ”/”:llä, sitä käytetään sellaisenaan.Muussa tapauksessa paketin nimi liitetään etuliitteeksi sen jälkeen, kun kaikki pistekirjaimet (.) on muutettu vinoviivoiksi (/).
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);}
Metodi resolveName
lisää paketin nimen etuliitteen, jos nimi ei ole absoluuttinen, ja poistaa etuliitteen alkuosan sisältävän ”/”-merkin, jos nimi on absoluuttinen. On mahdollista, vaikkakin harvinaista, että eri paketeissa olevat luokat jakavat saman resurssin.
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;}
Using Methods of java.lang.ClassLoader
Luokassa ClassLoader
on kaksi metodisarjaa resurssien käyttämiseen. Toinen joukko palauttaa InputStream
resurssin. Toinen joukko palauttaa URL-osoitteen. Metodit, jotka palauttavat InputStream
:n, ovat helppokäyttöisempiä ja tyydyttävät monia tarpeita, kun taas metodit, jotka palauttavat URL:n, tarjoavat pääsyn monimutkaisempaan tietoon, kuten Image ja AudioClip.
ClassLoader
muuttaa resursseja samalla tavalla kuin se hallitsee luokkia. ClassLoader
ohjaa, miten resurssin nimi liitetään sen sisältöön. ClassLoader
antaa myös metodeja järjestelmäresurssien käyttämiseen,analogisesti järjestelmäluokkien kanssa. Class
luokka tarjoaa joitakin mukavuusmetodeja, jotka delegoivat toimintoja ClassLoader
-metodeille.
Monet Java-ohjelmat käyttävät näitä metodeja epäsuorasti I18N (lokalisointi) API:n kautta. Toiset käyttävät niitä Class
:n metodien kautta.
Kohdassa ClassLoader
olevat menetelmät käyttävät annettua merkkijonoa resurssin nimenä soveltamatta mitään absoluuttista/relatiivista muunnosta (katso menetelmät kohdassa Class). Nimessä ei saa olla etumerkkiä ”/”.
Järjestelmäresurssit ovat resursseja, joita isäntäresurssi käsittelee suoraan. Ne voivat esimerkiksi sijaitaCLASSPATH:ssa.
Resurssin nimi on ”/”-merkillä erotettu tunnisteiden sarja. Class
-luokka tarjoaa mukavuusmetodeja resurssien käyttämiseen; metodit toteuttavat konventiota, jossa paketin nimi on etuliitteenä resurssin lyhyen nimen edessä.
Resursseja voidaan käyttää InputStream
– taiURL-muodossa.
Metodi getSystemResourceAsStream
palauttaa määritellyn järjestelmäresurssin anInputStream-tiedonsiirtovirran (InputStream) tai nollan, jos resurssia ei löydy. Resurssin nimi voi olla mikä tahansa järjestelmäresurssi.
Metodi getSystemResource
etsii järjestelmäresurssin annetulla nimellä. Se palauttaa resurssin URL-osoitteen tai nolla, jos se ei löydä resurssia. Kutsujava.net.URL.getContent()
URL-osoitteella palauttaa objektin, kuten ImageProducer
, AudioClip
tai InputStream
.
Metodi getResourceAsStream
palauttaa määritetyn resurssin InputStream
tai nollan, jos se ei löydä resurssia.
Metodi getResource
etsii resurssin, jolla on määritetty nimi. Se palauttaa resurssin URL-osoitteen tai nollan, jos se ei löydä resurssia. Kutsujava.net.URL.getContent()
URL-osoitteella palauttaaobjektin, kuten ImageProducer
, AudioClip
tai InputStream
.
Turvallisuus
Koska getResource()
tarjoaa pääsyn tietoihin,sillä on oltava hyvin määritellyt ja perustellut turvallisuussäännöt. Jos turvallisuusnäkökohdat eivät salli resurssin olevan näkyvissä jossakin turvallisuuskontekstissa, getResource()
-metodi epäonnistuu (palauttaa nollan), ikään kuin resurssia ei olisi lainkaan, tämä puuttuu olemassaolohyökkäyksiin.
Luokanlataajat eivät saa antaa pääsyä .class-tiedoston sisältöön sekä turvallisuus- että suorituskykysyistä. Se, onko .class-tiedoston URL-osoitteen saaminen mahdollista, riippuu erityispiirteistä, kuten alla on esitetty.
Ei ole määriteltyjä tietoturvaongelmia tai rajoituksia, jotka koskevat resursseja, jotka ei-järjestelmän luokanlataaja löytää.AppletClassLoader
tarjoaa pääsyn tietoihin, jotka ladataan lähdepaikasta joko yksittäin tai ryhmänä JAR-tiedoston kautta; näin ollen AppletClassLoader
:n tulisi soveltaa samoja checkConnect()
-sääntöjä käsitellessään URL-osoitteita getResource()
:n kautta.
Järjestelmä ClassLoader
tarjoaa pääsyn CLASSPATH:ssa oleviin tietoihin. CLASSPATH voi sisältää hakemistojaja JAR-tiedostoja. Koska JAR-tiedosto luodaan tarkoituksellisesti, sillä on erilainen merkitys kuin hakemistolla, johon asiat voivat päätyä satunnaisemmin. Erityisesti olemme tiukempia saamaan tietoa hakemistosta kuin JAR-tiedostosta.
Jos resurssi on hakemistossa:
-
getResource()
kutsut käyttävätFile.exists()
määrittämään, tehdäänkö vastaava tiedosto näkyväksi käyttäjälle. Muistutetaan, ettäFile.exists()
käyttäächeckRead()
-metodia security managerissa. - sama pätee myös
getResourceAsStream()
:lle.
Jos resurssi on JAR-tiedostossa:
-
getResource()
kutsut onnistuvat kaikkien tiedostojen kohdalla riippumatta siitä, onko kutsu tehty järjestelmäluokasta vai muusta kuin järjestelmäluokasta. -
getResourceAsStream()
kutsut onnistuvat muille kuin .class-luokan resursseille, samoin kuinjava.net.URL.getContent()
vastaaville URL-osoitteille.
Esimerkkejä
Tässä osassa on kaksi esimerkkiä asiakaskoodista. Ensimmäisessä esimerkissä käytetään ”absoluuttisten resurssien” nimiä ja perinteisiä mekanismeja Class
-olion saamiseksi.
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. }}
Tässä esimerkissä käytetään ”suhteellisten resurssien” nimiä ja kääntäjästä saatavaa mekanismia -experimental
-lipukkeen kautta Class
-olion saamiseksi.
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. }