2012-07-18 20 views
17

Ci sono 10 milioni di articoli e documenti là fuori su cosa sono i classloader Java e come/* perché * scrivere i propri ... ma tutti sembrano presumere alcune cose che non riesco a trovare un semplice rispondi a!Quando si attivano i programmi di caricamento classi Java?

Capisco il lavoro del classloader: leggere bytecode e costruirne un oggetto. Diversi classloader fanno in modo diverso, ecc

Ma avendo mai avuto a che il codice contro un'API class loader nel mio codice, e mai dover scrivere uno dei miei, sto avendo enormi difficoltà a comprendere quando un ClassLoader ' il proprio codice viene effettivamente attivato.

Per esempio:

public static void main(String[] args) { 
    Fizz fizz = new Fizz(); 
    fuzz.buzz(); 
} 

qui, abbiamo un oggetto Fizz. Prima che sia possibile creare un'istanza di Fizz, è necessario un caricatore di classi per avviare e caricare Fizz.class nella sua cache. Dove e quando succede?!?! Non è esplicitamente nel mio codice quindi deve essere implicitamente da qualche parte nel JRE ...?

tangenziale a questa domanda, se scrivo il mio programma di caricamento classe, dire, WidgetClassLoader e si desidera configurarlo per caricare sia tutte le classi della mia applicazione, o forse solo la mia Fizz.class, come faccio a "legare" questo WidgetClassLoader nella mia applicazione in modo che sa quale classloader usare? Il mio codice avrebbe dovuto chiamare esplicitamente questo classloader o sarebbe implicito come il primo esempio? Grazie in anticipo!

+0

È nel JRE, ovviamente. Leggi questo e Google per la configurazione personalizzata del programma di caricamento classe: http://www.javalobby.org/java/forums/t18345.html – duffymo

+0

@duffymo - guarda il mio commento sotto la risposta di Andre - Ho la stessa domanda per te! – IAmYourFaja

+0

Non vedo la necessità di scrivere mai un caricatore di classi per conto mio. Non una volta, durante tutto il tempo in cui ho scritto Java. E questo è dal 1,0 del 1997. Cosa ti fa pensare che ne hai bisogno? – duffymo

risposta

6

La tua domanda non è così banale come pensi ora.

L'esempio di Fizz: Quando viene caricato Fizz? Questo è definito nello JLS (Chapter 5.4: Linking). Non definisce quando viene caricato Fizz, ma fornisce garanzie sul comportamento visibile. Per la parte 'quando', se Fizz non può essere trovato, verrà lanciata un'eccezione dalla prima dichiarazione che accede a Fizz (Fizz fizz = new Fizz()). Sono abbastanza sicuro che sarà il nuovo Fizz() specificamente in questo caso, perché il lato destro dell'espressione viene prima evaulato.Nel caso in cui aveva scritto così:

Fizz fizz = null; 
fizz = new Fizz(); 

In questo caso il Fizz Fizz = null sarebbe già generare l'eccezione perché il suo primo accesso alla classe Fizz.

Chi carica Fizz? Quando una classe deve essere caricata, il classloader che 'appartiene' al codice che richiede la classe viene usato per ottenere la classe. Nell'esempio Fizz questo sarà il classloader che ha caricato la classe con il metodo principale. Naturalmente, il classloader può scegliere di delegare al proprio programma di caricamento di classe genitore se non può caricare Fizz da solo.

Come si utilizza JVM my ClassLoader? Ci sono due modi, esplicitamente o implicitamente. Esplicitamente: puoi caricare un corso attraverso il tuo classloader chiamando i suoi metodi. Implcitly: quando esegui codice (ovvero metodi o inizializzatori) da una classe che è già stata caricata dal classloader e un riferimento di classe deve essere risolto nel processo, il classloader verrà automaticamente utilizzato perché è il classloader che ha caricato il codice in il primo posto.

+0

Questo risponde alla parte di cui non ero sicuro circa così +1 da me :-) –

+0

+1 non vale nulla che il "mio" ClassLoader sia 'Thread.currentThread(). GetContextClassLoader()' cioè ogni Thread ha un caricatore di classi predefinito e possono essere diversi. –

+1

@Durandal, Informazioni sul caricamento esplicito e implicito, nell'esempio di Fizz, è sicuro che non verrà utilizzato il caricatore di classi personalizzato .. giusto? In sostanza, per il caricamento implicito, un caricamento esplicito deve iniziare il processo. Qui può usare Class.forName() per la classe Fizz per essere caricato in modo esplicito o mettere la classe Fizz nel percorso della classe in modo che JVM lo carichi. La conclusione è che il caricatore di classi personalizzato funzionerà solo con un approccio esplicito, per la prima volta. Correggimi se sbaglio – AKS

3

Java ha un caricatore di classi predefinito. Cerca le dichiarazioni di classe nel percorso di classe predefinito. Se scrivi il tuo caricatore di classi puoi (e dovresti) impostare il caricatore della classe genitore. Questo sarebbe l'impostazione predefinita se non ne hai un'altra. Se non lo fai, il tuo programma di caricamento classi non sarebbe in grado di trovare le classi API java. Se java cerca una classe, non inizia a cercare con il caricatore di classi personalizzato ma con il caricatore della classe genitore. Se questo ha un genitore inizia lì e così via. Solo se non è possibile trovare una classe, il successivo caricatore di classe figlio viene utilizzato per riprovare. Di nuovo questo continua finché ci sono bambini. Se la classe non viene trovata da nessuno dei caricatori della catena, viene lanciato un numero ClassNotFoundException.

Naturalmente Java utilizza solo il vostro caricatore di classe se si imposta come classe predefinita loader primo (chiamando Thread.currentThread().setContextClassLoader()) o caricare la classe manualmente (chiamando loadClass()).

Non sono sicuro quando viene richiamato il programma di caricamento classi. Penso che sia invocato all'avvio del programma (su tutte le classi dichiarate come import) o al primo utilizzo di una classe (dichiarazione variabile o chiamata costruttore).

+0

Grazie @Andre, ma ancora una volta, questa è una risposta alla domanda "* Come funzionano i classloader? *" Capisco il gerarchia del classloader - quello che non capisco è quando e dove il classloader predefinito di JRE esegue il codice che crea il mio 'Fizz.class'. – IAmYourFaja

+0

Prova a impostare un punto di interruzione in 'java.lang.ClassLoader' nel metodo 'loadClass()'. –

+0

Ho pensato e modificato la mia risposta. Mi dispiace ma non sono sicuro su quest'ultima parte. –

0

L'effettiva creazione della classe si verifica in defineClass. La classe viene creata utilizzando una matrice di byte da una qualsiasi delle varie origini.

Il percorso normale arrivare a defineClass (che è protected) è attraverso findClass (che, naturalmente, è anche protected). Quindi il solito punto d'ingresso è loadClass ->findClass ->defineClass. Ma ci sono altri percorsi per casi speciali.

(Il tutto è abbastanza contorta, e rappresenta una storia di aggiunta di strati di protezione è diventata più complessa e le modalità di accesso più varie.)

0

Se siete interessati a classloader e quando e come funzionano , puoi anche dare un'occhiata a the OSGi specification - mi sembra una lettura molto interessante per te. OSGi è un framework per Java che fornisce modularità, separazione dei codici e gestione del ciclo di vita e che è molto popolare al momento (ad esempio, Eclipse stesso è basato su uno).

OSGi utilizza pesantemente i programmi di caricamento di classi e vi è una spiegazione molto semplice quando e come tutto ciò che avviene con il caricamento di classe avviene all'interno delle specifiche. Fondamentalmente hanno un classloader bundle separato per ogni bundle (è così che vengono chiamati i moduli) e questi classloader si prendono cura delle dipendenze e recuperano la classe corretta dall'altro bundle.

Problemi correlati