2015-10-15 1 views
1

Dans mon projet (lors de l'exécution): Le chargeur de classe d'application est chargé avec un ensemble de classes. Et j'ai un chargeur de classe d'utilisateur, chargé avec un ensemble de classes.Comment ajouter/charger une classe au chargeur de classe d'extension au moment de l'exécution?

Maintenant, il existe une classe dans le chargeur de classe d'application qui tente de charger une classe qui n'existe pas dans le chargeur de classe d'application, mais qui existe dans le chargeur de classes d'utilisateurs.

Par exemple: une classe dans le chargeur de classe d'application ayant un code comme

this.getClass().getClassLoader().loadClass("user class"). 

Note: Je n'ai pas accès à la classe (qui est dans le chargeur de classe d'application) et je peux cant ajouter la classe à charger au chargeur de classe d'application.

Comment charger une telle classe?

Ce scénario se passe dans la classe DriverManager:

Je DriverManager dans la catégorie chargeur d'application et classe pilote dans chargeur de classe utilisateur. Et DriverManager essaie de charger la classe de pilote dans Chargeur de classe d'application et il ne parvient pas à charger la classe. Donc je veux ajouter la classe de pilote à l'application ou le chargeur de classe d'extension à l'exécution. Mais comment le faire?

+0

Quelle est la hiérarchie entre Application Classloader et User Classloader? L'un ou l'autre est-il un chargeur de classe parent de l'autre, ou est-il totalement indépendant (ayant un parent commun quelque part)? Je suppose que AppCL sera le parent de UserCL. – gaborsch

+0

oui, classloader d'application est le parent du chargeur de classe User. –

Répondre

3

Essayez d'utiliser le fil classloader:

Thread.currentThread().getContextClassLoader() 

Dans votre exemple:

Class<?> driverClass = Thread.currentThread().getContextClassLoader().loadClass("user class name") 

Je suppose que ces classes d'utilisateurs mettra en œuvre une interface définie (chargée) dans classloader d'application, donc vous allez les traiter à travers cette interface. Dans ce cas, il ne devrait pas y avoir de problème à utiliser de telles classes chargées.

Vous pouvez instancier une instance d'objet de celle avec le constructeur par défaut (vous devez prendre un certain nombre d'exceptions, cependant):

userDriver = (Driver) driverClass.newInstance(); 

Si vous souhaitez utiliser un autre constructeur (par exemple avec un paramètre String):

Constructor<?> c = driverClass.getConstructor(String.class); 
userDriver = (Driver) c.newInstance("String param to constructor"); 
+0

GaborSch: Je n'ai pas accès à la classe loader de classe d'application. Si j'utilise Thread Context, il chargera dans le chargeur de classe d'utilisateur et ne sera pas disponible pour le chargeur de classe d'application. Vérifiez s'il vous plaît. –

+0

Vous n'avez pas besoin d'accéder au classloader. Vous avez besoin d'une instance de cette classe, qui doit implémenter votre interface 'Driver', et vous pouvez gérer cette instance Driver. Veuillez vérifier la réponse mise à jour. – gaborsch

+0

Cela signifie que DriverManager doit utiliser Thread.currentThread(). GetContextClassLoader() au lieu de this.getClass(). GetClassLoader() pour charger la classe de pilote.Parce que DriverManager utilise this.getClass(). GetClassLoader() il obtient le chargeur de classe Application et n'a pas pu charger, mais le pilote est présent dans Thread.currentThread(). getContextClassLoader(). –

0

J'ai deux solutions pour aller,

1) Remplacer classe gestionnaire de pilote et d'utiliser T hread.currentThread(). getContextClassLoader() au lieu de this.getClass(). getClassLoader() pour charger la classe de pilote.

2) Obtenir une instance de chargeur de classe System et une API protégée dans le chargeur de classe système addURL(), qui ajoute des ressources au chargeur de classe système au moment de l'exécution. À l'aide de la réflexion, si vous pouvez appeler l'API addURL(), la classe de pilote sera accessible au gestionnaire de pilotes au niveau du chargeur de classe système. Voici le code sanppit

URL[] urls = new URL[]{jarFile.toURL()}; 
    ClassLoader cl = ClassLoader.getSystemClassLoader() 
    if (cl instanceof URLClassLoader) { 
     URLClassLoader ul = (URLClassLoader) cl; 

     // addURL is a protected method, but we can use reflection to call it 
     Class<?>[] paraTypes = new Class[1]; 
     paraTypes[0] = URL.class; 
     Method method = URLClassLoader.class.getDeclaredMethod("addURL", paraTypes); 
     method.setAccessible(true); 
     Object[] args = new Object[1]; 
     for (int i = 0; i < urls.length; i++) { 
      args[0] = urls[i]; 
      method.invoke(ul, args); 
     } 
    } 

Note: De cette façon, vous ne pouvez ajouter des ressources pour le chargeur de classe système, mais vous ne pouvez pas annuler l'enregistrement ajouté des ressources à partir des questions de résultats classe loader.Which si vous avez des versions de pots.