Java

Problem z ClassLoaderem

  • 2 komentarze
  • 785 odsłon
  • Oceń ten tekst jako pierwszy

Problemy z klasami


Jedną z bardziej znienawidzonych przeze mnie rzeczy w języku Java jest ClassLoader. Niestety rządzi się on swoimi własnymi prawami i wszelkie modyfikacje jego ustawień są niemal niemożliwe. Poniżej prezentuję listę problemów, które najbardziej utrudniają mi życie wraz z rozwiązaniami (o ile są możliwe i o ile je znalazłem ;) ).

Problem 1. ładowanie nowych wersji klas


Problem wytłumaczę na przykladzie.
Mamy jakiś modułowy system, w którym moduł główny ładuje i uruchamia inne moduły. W czasie rozwoju oprogramowawnia zmieniamy kod tylko w jednym z modułów pobocznych. Problem ujawnia się w ten sposób, że jeśli VM Javy załaduje raz klasę o danej nazwie, to przy powtórnym tworzeniu egzemplarza tej klasy brany jest kod poprzednio wczytany przez VM. Zatem nawet jeśli nowy kod jest w znanej ścieżce VM, nie zostanie on uwzględniony.

Rozwiązenie:
Brak! Jedyne co można zrobić, to uruchomić wszystko od początku. Może kiedyś przy czyszczniu pamięci VM skasuje załadowany kod, ale mi nie udało sie tego doczekać ;)

Problem 2. ścieżka dostępu


Problem również związany z ładowaniem klas. Wszysko jest proste, jeśli wiadomo gdzie znajdują się wszystkie potrzebne klasy. Wtedy wystarczy podać parametr classpath przy uruchamianiu VM i wszystko gra. Gorzej, gdy potrzeba dodać informację o ścieżce do klas dynamicznie w trakcie działania programu. Formalnie jest to niemożliwe, ale....

Rozwiązanie:
Poniżej prezentuję uproszczoną wersję klasy, która pozwala w sposób niezbyt "legalny" poradzić sobie z tym problemem. Jest to nieco zmodyfikowany i uproszczony kod znaleziony gdzieś na jakimś forum dyskusyjnym (tak dawno, że nie pamiętam gdzie).

import java.io.*;
import java.net.*;
import java.lang.reflect.*;
 
public class SetPath
{
  private static final Class[] parameters = new Class[]{URL.class};
 
  public static void addFile(String s) throws IOException
  {
    File f = new File(s);
    addFile(f);
  }
 
  public static void addFile(File f)
  {
    try {
      addURL(f.toURL());
    } catch ( MalformedURLException e ) {}
  }
 
  static void addURL(URL u)
  {
    URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
    Class sysclass = URLClassLoader.class;
    try {
      Method method = sysclass.getDeclaredMethod("addURL",parameters);
      method.setAccessible(true);
      method.invoke(sysloader,new Object[]{ u });
      } catch (Throwable t) {
        t.printStackTrace();
      }
  }
}


W miarę odkrywania i pokonywania problemów oraz w miarę wolnego czasu będę tutaj dopisywał moje nowe odkrycia. O ile w ogóle będzie zainteresowanie ;)

ash

2 komentarze

Olamagato 2009-09-28 01:39

Przed jakimikolwiek zabawami z dynamicznym ładowaniem klas warto wywołać coś takiego:
Compiler.disable();
Powoduje to dezaktywację JIT, a tym samym rozwiązanie problemu z rzekomym bugiem dynamicznego ładowania klas. Aktywny kompilator zawsze zmusza JVM do używania raz wstępnie skompilowanego kodu. A to uniemożliwia w praktyce dynamiczne ładowanie lub podmianę klas. Na całą resztę kodu nie związanego z ładowaniem klas należy z powrotem przywrócić JIT przez Compiler.enable();.

Olamagato 2008-12-10 11:38

Bardzo przydatny dla mnie artykuł.