19 Nisan 2018 Perşembe

ClassLoader Sınıfı

Giriş
ClassLoader soyut (abstract) bir sınıf. ClassLoader çalışma esnasında bir sınıf veya arayüz ile karşılaşınca onu yükler. Açıklaması şöyle
ClassLoaders are architected so that at start-up the JVM doesn't need to know anything about the classes that will be loaded at runtime.
Initially when a JVM starts up, nothing is loaded into it. The class file of the program being executed is loaded first and then other classes and interfaces are loaded as they get referenced in the bytecode being executed.
1. Arayüzü gerçekleştiren sınıflardan birisi URLClassLoader.
2. Diğeri sun.misc.Launcher$AppClassLoader. Bu sınıf .class uzantısına sahip derlenmiş java kodunu  çalıştırınca kullanılır.
3. Bir başkası ise ExtClassLoader. Bu sınıf jar dosyasını çalıştırınca kullanılır.

Defining Loader Nedir
Açıklaması şöyle
If L creates C directly, we say that L defines C or, equivalently, that L is the defining loader of C.
Initiating Loader Nedir
Açıklaması şöyle
When one class loader delegates to another class loader, the loader that initiates the loading is not necessarily the same loader that completes the loading and defines the class. If L creates C, either by defining it directly or by delegation, we say that L initiates loading of C or, equivalently, that L is an initiating loader of C.
Classloader'lar şöyle çalışsın.
L->Lp->Lq
L sınıfı yükleme işlemini Lp'ye, Lp ise Lq'ya söylesin. Lq yükleme işlemini bitirince Defining Loader, L ve Lp ise Initiating Loader olurlar.

Java EE Container ve Custom Classloader
Açıklaması şöyle.
First of all, Java EE containers (like Tomcat, GlassFish and so on) uses a custom ClassLoader (let calling it CW) for loading web application classes. Classes that are not part of the web application (like ThreadLocal and other JDK classes) are loaded by another ClassLoader (C0).

If a class loaded by C0 references something loaded by CW, this reference doesn't allow the garbage collector cleaning all the involved instances (not even when the application is undeployed!) and this will cause the ClassLoader leak. So, after a sequence of deployment and undeployment, your server will run out of memory.
Elimizde şöyle bir kod olsun.
public class MyCounter {
  private int count = 0;

  public void increment() {
    count++;
  }

  public int getCount() {
    return count;
  }
}

public class MyThreadLocal extends ThreadLocal<MyCounter> {
}

public class LeakingServlet extends HttpServlet {
  private static MyThreadLocal myThreadLocal = new MyThreadLocal();

  protected void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {

  MyCounter counter = myThreadLocal.get();
  if (counter == null) {
    counter = new MyCounter();
    myThreadLocal.set(counter);
  }

  response.getWriter().println(
    "The current thread served this servlet " + counter.getCount()
    + " times");
    counter.increment();
  }
}
Bu kod Classloader leak'e sebep olabilir. Çünkü ServletKodu CW tarafından yüklenir. ThreadLocal ise C0 tarafından yüklenir. Uygulama undeploy edilse bile CW->kullanır->C0 olduğu için CW nesnesi silinemez.

constructor
Her sınıf kendisini yükleyen Classloader nesnesini bilir. Şöyle yaparız.
ClassLoader classLoader = Test.class.getClassLoader();
Thread ile şöyle yaparız.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
getResource metodu
Bir Uri döndürür. Erişilen dosya veya dizinin dosya sistemi üzerinde olması gerekir.
Örnek
Dosya için şöyle yaparız.
System.out.println(classLoader.getResource("foo/Test.class"));
Çıktı olarak şunu alırız.
file:/C:/Users/Jon/Test/foo/Test.class
Örnek
Dizin için şöyle yaparız.
ClassLoader classLoader = this.getClass().getClassLoader();
Path configFilePath = Paths.get(classLoader.getResource("config").toURI());    
getResources metodu
Tüm jar'ların META-INF dizini dolaşmak için şöyle yaparız.
Enumeration<URL> en=getClass().getClassLoader().getResources("META-INF");
if (en.hasMoreElements()) {
  URL url=en.nextElement();
  ...
}
getResourceAsStream metodu
ClassLoader İle Resource Yüklemek yazısına taşıdım.

getSystemClassLoader metodu
Java 9 ile açıklaması şöyle.
The application class loader is no longer an instance of java.net.URLClassLoader (an implementation detail that was never specified in previous releases). Code that assumes that ClassLoader::getSytemClassLoader returns a URLClassLoader object will need to be updated.
Java 9 ile şu kod çalışmıyor.
URL[] ressources = ((URLClassLoader) classLoader).getURLs();
loadClass metodu
Metodun imzası şöyle
public Class<?> loadClass(String name) throws ClassNotFoundException;
Şöyle yaparız.
package javaReflect.test;

public class PrivateCar {

  private String color;

  protected void drive() {
    System.out.println("this is private car! the color is:" + color);
  }
}

ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass("javaReflect.test.PrivateCar");



Hiç yorum yok:

Yorum Gönder