Bu orijinal soruyu cevaplamıyor, ancak soru herhangi bir ContextClassLoader
sorgu için yüksek dereceli ve bağlantılı olduğundan, bağlam sınıfı yükleyicinin ne zaman kullanılması gerektiği ile ilgili soruyu cevaplamanın önemli olduğunu düşünüyorum. Kısa cevap: asla bağlam sınıfı yükleyiciyi kullanmayın ! Ancak getClass().getClassLoader()
, ClassLoader
parametresi eksik bir yöntemi çağırmanız gerektiğinde bunu ayarlayın .
Bir sınıftan kod başka bir sınıf yüklemeyi istediğinde, kullanılacak doğru sınıf yükleyici, arayan sınıfı ile aynı sınıf yükleyicisidir (yani getClass().getClassLoader()
). Bu, işlerin% 99.9'unun çalışma biçimidir, çünkü JVM, yeni bir sınıf örneği ilk kez oluşturduğunuzda, statik bir yöntemi çağırdığınızda veya statik bir alana eriştiğinizde budur.
Yansıma kullanarak bir sınıf oluşturmak istediğinizde (örneğin, yapılandırılmış adlandırılmış bir sınıfın serileştirilmesi veya yüklenmesi gibi), yansımayı yapan kitaplık , uygulamadanClassLoader
bir parametre olarak alarak her zaman uygulamaya hangi sınıf yükleyicinin kullanılacağını sormalıdır . (İnşa edilmesi gereken tüm sınıfları bilen) uygulama bunu geçmelidir getClass().getClassLoader()
.
Sınıf yükleyici almanın başka bir yolu yanlıştır. Gibi bir kütüphane kullanımları kesmek durumunda Thread.getContextClassLoader()
, sun.misc.VM.latestUserDefinedLoader()
ya sun.reflect.Reflection.getCallerClass()
da API eksikliğinden kaynaklanan bir hatadır. Temel olarak, Thread.getContextClassLoader()
sadece ObjectInputStream
API'yi tasarlayan kişi ClassLoader
parametre olarak kabul etmeyi unuttuğu ve bu hata Java topluluğunu bugüne kadar perdelediği için var.
Bununla birlikte, birçok JDK sınıfı, bazı sınıf yükleyicilerin kullanmasını tahmin etmek için birkaç hack'ten birini kullanır. Bazıları ContextClassLoader
(paylaşılan bir iş parçacığı havuzunda farklı uygulamalar çalıştırdığınızda veya ayrıldığınızda ContextClassLoader null
başarısız olur), bazıları yığını (sınıfın doğrudan arayanı bir kütüphane olduğunda başarısız olur) kullanır, bazıları sistem sınıfı yükleyiciyi kullanır (sadece sınıftaki sınıfları kullanmak için belgelendiği sürece iyidir CLASSPATH
) veya bootstrap sınıf yükleyicisi ve bazıları yukarıdaki tekniklerin (yalnızca işleri daha karmaşık hale getirir) öngörülemeyen bir kombinasyonunu kullanır. Bu, dişlerin çok fazla ağlamasına ve gıcırdamasına neden oldu.
Böyle bir API kullanırken, önce sınıf yükleyiciyi parametre olarak kabul eden yöntemin aşırı yüklenmesini bulmaya çalışın . Mantıklı bir yöntem yoksa, ContextClassLoader
API çağrısından önce ayarlamayı (ve daha sonra sıfırlamayı) deneyin :
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// call some API that uses reflection without taking ClassLoader param
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
ClassB
sınıf yolunda olması gerektiğini söylüyorsunuz ? Yükleyicisinin sınıf yolunda olmasa bile başarıyla yüklenebilmesi için geçersiz kılınması mümkün değil mi?ClassA
ClassA
ClassA
loadClass()
ClassB
ClassB