Come funziona Class.forName ()?

Ho appena saputo del java.sql package . Utilizza Class.forName() per caricare dynamicmente il driver che estende DriverManager . Quindi otteniamo la connessione utilizzando il metodo DriverManager.getConnection() .

Quindi come funziona l’intera cosa?
In che modo la class DriverManager sa come ottenere la connessione senza utilizzare il nome class del driver effettivo.

Inoltre possiamo usare Class.forName () per applicazioni personalizzate … se questo è spiegato con un esempio, sarò molto felice.

Class.forName carica semplicemente una class, inclusa l’esecuzione dei suoi inizializzatori statici, in questo modo:

 class Foo { static { System.out.println("Foo initializing"); } } public class Test { public static void main(String [] args) throws Exception { Class.forName("Foo"); } } 

Tutto il resto della procedura di cui parli è specifico di JDBC. Il driver – che implementa Driver , non estende DriverManager – registra semplicemente un’istanza appropriata usando DriverManager.registerDriver . Quindi, quando DriverManager deve trovare un driver per una particolare stringa di connessione, chiama acceptsURL su ciascun driver registrato a turno fino a quando uno dice “Sì, posso essere il driver per quella connessione”.

Si noti che questo modo di registrare i driver è ragionevolmente vecchio stile – guarda i documenti per DriverManager per i modi più moderni di ottenere una fonte di dati.

Class.forName(..) carica e inizializza la class di destinazione. Ciò a sua volta significa che i blocchi di inizializzazione statici vengono richiamati (codice definito in static { .. } .

Se si guarda, ad esempio, il driver di MySQL, in quel blocco statico il driver si registra da solo: DriverManager.registerDriver(new Driver());

È ansible omettere Class.forName(..) e registrare autonomamente il driver se è ansible “permettersi” la dipendenza in fase di compilazione dal driver di MySQL.

Detto questo, raramente sarà rilevante utilizzare Class.forName(..) per inizializzare le classi dall’applicazione, poiché la dipendenza in fase di compilazione non è un problema.

Si noti inoltre che Class.forName(..) non è più necessario per JDBC dalla versione 4. Utilizzando il meccanismo del provider di servizi è ansible istruire il gestore di driver su cosa caricare da una proprietà di sistema.

Quando creiamo un’istanza di una class usando un nuovo operatore, fa due cose

  1. Carica la class nella memoria, se non è caricata, il che significa creare una rappresentazione in-memory della class dal file .class in modo che un’istanza possa essere creata al di fuori di essa. Ciò include l’inizializzazione delle variabili statiche (risoluzione di quella class)
  2. crea un’istanza di quella class e memorizza il riferimento alla variabile.

Class.forName fa solo la prima cosa. Carica la class in memoria e restituisce tale riferimento come un’istanza di Class. Se vogliamo creare un’istanza, possiamo chiamare il metodo newInstance di quella class. che invocherà il costruttore predefinito (nessun costruttore di argomenti). Notare che se il costruttore predefinito non è accessibile, il metodo newInstance genererà un IllegalAccessException . e se la class è una class astratta o un’interfaccia o non ha un costruttore predefinito, allora genererà una InstantiationException . Se un’eventuale eccezione si alza durante la risoluzione di quella class, genererà un’eccezione ExceptionInInitializerError .

Se il costruttore predefinito non è definito, dobbiamo richiamare il costruttore del defiend usando l’API di reflection.

Ma il vantaggio principale con Class.forName è che può accettare il nome della class come argomento String. Quindi possiamo passare il nome della class in modo dinamico. Ma se creiamo un’istanza di una class utilizzando un nuovo operatore, il nome della class non può essere modificato dynamicmente.

Class.forName() inturn chiamerà il metodo loadClass del chiamante ClassLoader (ClassLoder della class da cui viene richiamato Class.forName ).

Per impostazione predefinita, Class.forName() risolve quella class. il che significa inizializzare tutte le variabili statiche all’interno di quella class. lo stesso può essere modificato utilizzando il metodo sovraccarico di Class.forName(String name,boolean initialize,ClassLoader loader)

Il motivo principale per il caricamento del driver jdbc usando Class.forName() è, il driver può cambiare dynamicmente. nel blocco statico tutti i driver creeranno un’istanza di se stessi e registreranno tale class con DriverManager utilizzando il metodo DriverManager.registerDriver() . Poiché Class.forName(String className) per impostazione predefinita risolve la class, inizializzerà l’inizializzatore statico. Quindi, quando chiamiamo Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver") , la class Driver verrà caricata, instanciata e registrata con DriverManager

Quindi se stai usando il nuovo operatore devi fare le seguenti cose.
Codice:

 Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver(); DriverManager.registerDriver(drv); 

Il motivo per cui Class.forName() viene spesso citato negli esempi SQL, è perché non c’era alcuna magia per dire a JDBC DriverManager come mappare l’URL JDBC fornito a un driver reale.

Ad esempio “mysql” dovrebbe mappare su una determinata class MySQL, mappe “sottili” per la class Oracle, “as400” si associa alla class DB2 / 400.

Caricando esplicitamente la class, questo consentiva di eseguire il codice all’interno della class registrandosi con il driverManager.

In questi giorni sono presenti i ganci magici che consentono alla JVM di individuare automaticamente i driver (se nuovi), quindi la chiamata è superflua, ma per abitudine molti lo usano ancora.