Klassen dynamisch laden mit Class.forName()

von Veit Weber

Einführung

Mit Java ist das Erzeugen von Objekten einer dynamisch geladenen Klasse zur Laufzeit möglich.
Dieses Verfahren wird zum Beispiel angewandt, wenn mittels Java Database Connectivity (JDBC) auf eine relationale Datenbank zugegriffen wird. Zu den Aufgaben von JDBC gehört u.a. das Verwalten von Verbindungen zur Datenbank, das Weiterleiten von SQL-Befehlen und die Aufbereitung der Ergebnisse aus SQL-Befehlen, sodass sie in Java weiterverarbeitet werden können. Die JDBC-Schnittstelle bietet Zugriff auf Datenbanken verschiedener Hersteller und ist nicht an eine bestimmte Datenbankart gebunden. Damit ist der Hersteller in der Pflicht, Treiber für sein Datenbanksystem bereitzustellen, welche die JDBC-Spezifikation implementieren. Diese entsprechenden Treiber werden im Klassenpfad der Anwendung abgelegt und mit Class.forName() zur Laufzeit geladen.
Ein weiteres Beispiel wäre, eine Art „Plug-In“-System: Wenn die Klasse dynamisch geladen wird, besteht die Möglichkeit, deren entsprechende Funktionalität zu ändern und die neue Version im Klassenpfad abzulegen. Beim nächsten Laden der Klasse, wird die neue Version geladen, ohne dass die komplette Anwendung neu deployt werden musste.

Die Meta-Klasse „Class“ – Ein wenig Theorie

Objekte der Klasse Class können (eingeschränkt) als Meta-Objekte bezeichnet werden, denn sie stellen alle Informationen einer Klasse zur Verfügung, die sie repräsentieren. Jede Klasse ist innerhalb der Java Virtual Machine (JVM) eindeutig einem Class-Objekt zugeordnet. Diese Eindeutigkeit ist zum Beispiel wichtig für die Synchronisation von Threads. Class-Objekte können nicht durch den Entwickler erzeugt werden, sie werden automatisch von der JVM erstellt.

Mit Class-Objekten kann man

  • Klassen dynamisch in die JVM laden
  • Den vollständigen Klassennamen eines Objektes ermitteln (getName())
  • Verschiedenste Informationen über das repräsentierte Objekt ermitteln (getMethods(), getFields(),…). Dieses Verhalten wird als Reflection bezeichnet.
  • Ein neues Objekt des repräsentierten Objekts erstellen
  • Oberklassen ermitteln

In diesem Artikel liegt der Fokus auf dem dynamischen Laden von Klassen. Daher soll an dieser Stelle die Methode forName() etwas näher erläutert werden.

Die Methode "Class.forName()"

Der Aufruf der Methode Class.forName("x") lädt die Klasse "X" dynamisch zur Laufzeit. Das heißt, die Klasse wird von der JVM geladen und der statische Initalisierer der Klasse wird aufgerufen. Ein Beispiel:

Klasse DynamicClass (wird dynamisch geladen)

package com.ulc.jnotes.demo;

class DynamicClass
{
  public DynamicClass()
  {
    System.out.println("Constructor: DynamicClass");
  }

  static
  {
    System.out.println("Static: DynamicClass");
  }
}

Hauptprogramm

public class Program
{
  public static void main(String[] args)
  {
    try
    {
      Class c = Class.forName("com.ulc.demo.jnotes.DynamicClass");
      DynamicClass dClass = (DynamicClass) c.newInstance();
    }
    catch (ClassNotFoundException e)
    {
      …
    }
    catch (InstantiationException e)
    {
      …
    }
    catch (IllegalAccessException e)
    {
      …
    }
  }
}

Ausgabe

Static: DynamicClass
Constructor: DynamicClass

XPages mit JDBC verdrahten – Ein Beispiel

Um beispielsweise ein RepeatPanel auf einer XPage mit Daten aus einer relationalen Datenbank zu befüllen, sind folgende Schritte nötig:
Zunächst wird eine ManagedBean benötigt, die sich um den Datenbankzugriff und die Datenbindung an die XPage kümmert. Wie sie eine ManagedBean im Domino Designer erstellen erfahren Sie hier.
Neben der Datenbindung wird eine Methode zum Auslesen von Daten aus der SQL-Datenbank benötigt.

public void executeSqlQuery() throws SQLException
{
  PreparedStatement stmt = null;
  Connection conn = null;
		
  try
  {
    Class.forName("oracle.jdbc.driver.OracleDriver");

    String url = "jdbc:oracle:thin:@192.168.6.102:1521:xe";
    String queryString = "SELECT username FROM usertable WHERE username = ?";
    String username = "TestNutzername";
    conn = DriverManager.getConnection(url, "DBUser", "123456");

    stmt = conn.prepareStatement(queryString);
    stmt.setString(1, username);
    ResultSet rset = stmt.executeQuery();
    while (rset.next())
    {
      // daten weiterverarbeiten
    }
    stmt.close();
    conn.close();
  }
  catch (ClassNotFoundException cfEx)
  {
    cfEx.printStackTrace();
  }
  catch (SQLException sqlEx)
  {
    sqlEx.printStackTrace();
  }
  finally
  {
    if(stmt != null)
      stmt.close();
			
    if(conn != null)
      conn.close();
  }
}

Mit der Anweisung Class.forName("oracle.jdbc.driver.OracleDriver"); wird die JVM angewiesen, im Klassenpfad nach einem passenden Treiber (genauer: einer passenden Klasse) zu suchen und den statischen Initialisierungsteil auszuführen. In diesem Initialisierungsteil registriert sich der Treiber in der JVM. Es muss also kein eigenes Objekt erzeugt werden.
Der Rest ist reines JDBC. Eine Verbindung mit der Oracle-Datenbank wird hergestellt, eine SQL-Abfrage ausgeführt und das Ergebnis kann weiterverarbeitet werden und zum Beispiel innerhalb der Bean an eine Methode gebunden werden, die wiederum vom RepeatPanel aufgerufen wird.
Einige Klassen für Datenbanktreiber: 

DB2/Derby
com.ibm.db2.jcc.DB2Driver
Oracle
oracle.jdbc.driver.OracleDriver
mSQL
com.imaginary.sql.msql.MsqlDriver
MySQL
com.mysql.jdbc.Driver4
Borland JDataStore
com.borland.datastore.jdbc.DataStoreDriver
Borland Interbase
interbase.interclient.Driver
Adabas D
de.sag.jdbc.adabasd.ADriver
SYBASE ASE
com.sybase.jdbc.SybDriver
IDS Server
ids.sql.IDSDriver

 

Dynamisches Laden von Klassen mit der JVM des Domino-Servers 8.5.2

Mit Domino 8.5.2 und höher hat IBM die Sicherheitsrichtlinien überarbeitet, so dass der vorliegende Code nicht mehr fehlerfrei funktioniert. Standardmäßig ist das dynamische Laden von Klassen am Domino Server deaktiviert. Sollten Sie folgende Fehlermeldung bekommen:

Access denied (java.lang.RuntimePermission getClassLoader)

Müssen Sie in der Datei „...\Lotus\Domino\jvm\lib\security\java.policy“ folgenden Eintrag hinzufügen:

permission java.lang.RuntimePermission "getClassLoader";
erstellt am 18.05.2012 - bewertet mit 5 von 5
Abgelegt unter: Agent, Domino, Java, Notes

Bewerten Sie diesen Artikel:


Senden Sie einen Kommentar

Name
E-Mail
Kommentar
FrageGATY-98248M (bitte diesen Wert in unten stehendes Feld eintragen)
Antwort