Java Classloader
8802 ワード
JavaクラスローダはBootrapクラスローダ、拡張クラスローダ、アプリケーションクラスローダ、カスタムクラスローダに分けられます.このうち、ルート・クラス・マウンタと拡張クラス・マウンタは直接制御できません.アプリケーション・クラス・マウンタとカスタム・マウンタは、クラスを自分でマウントするために使用できます.
アプリケーションクラス・ローダはクラスをアプリケーションクラスClassloaderにマウントし、カスタムクラス・ローダはクラスをカスタム(URLClassloaderを使用するなど)にマウントし、異なるカスタムClassloaderは同じClassをマウントし、クラス内の静的変数であっても互いに隔離され、相手の付与操作の影響を受けない独立したメモリ領域を有する.
1.アプリケーションクラスローダの例:
このメソッドがクラスをマウントすると、クラスのメモリ領域がアプリケーションマウントクラスに適用されます.
2、カスタムクラスマウンタの例:
3、カスタムクラスローダテスト
URLClassloaderを使用してマウントするには、次の手順に従います.
ClassLoaderTest.JAva,参照1.
4、既存のカスタムクラスマウンタにマウントする
5、これらのテストのクラスは、現在のプロジェクトのクラスパスの下に置かないでください.それ以外の場合、Bootrapクラスマウンタは自動的にマウントされるため、ロードされたクラスを再ロードするのは無効です.
6、
アプリケーションクラス・ローダはクラスをアプリケーションクラスClassloaderにマウントし、カスタムクラス・ローダはクラスをカスタム(URLClassloaderを使用するなど)にマウントし、異なるカスタムClassloaderは同じClassをマウントし、クラス内の静的変数であっても互いに隔離され、相手の付与操作の影響を受けない独立したメモリ領域を有する.
1.アプリケーションクラスローダの例:
/**
* jar
* @param file
* @throws Exception
*/
public static void loadJar(String file) throws Exception {
JarFile jar = new JarFile(file);
Enumeration<JarEntry> entries = jar.entries();
ClassLoader cl = (ClassLoader) Thread.currentThread().getContextClassLoader();
// ClassLoader defineClass(String, byte[], int, int) , protected
Method md1 = java.lang.ClassLoader.class.getDeclaredMethod("defineClass",
String.class, byte[].class, int.class, int.class);
md1.setAccessible(true);
String name;
// jar
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class")) {
name = entry.getName();
name = name.substring(0, name.length() - 6);
name = name.replaceAll("/", ".");
InputStream is = jar.getInputStream(entry);
ByteArrayOutputStream dataOut = new ByteArrayOutputStream();
byte[] packData = new byte[2048];
int readLen = 0;
while (-1 != (readLen = is.read(packData))) {
dataOut.write(packData, 0, readLen);
}
if (dataOut.size() <= 0) {
throw new ClassNotFoundException(name);
}
byte[] classFile = dataOut.toByteArray();
System.out.println("class name:" + name);
md1.invoke(cl, name, classFile, 0, classFile.length);
}
}
}
/**
*
*/
public void loadTest(){
String file = "D:\\test2\\TestedClass.jar";
try {
ClassLoaderTest.loadJar(file);
Class<?> c = Class.forName("dictquery.Hello");
Method[] ms = c.getDeclaredMethods();
Object obj = c.newInstance();
for(int i=0;i<ms.length;i++){
Method m = ms[i];
System.out.println("Method:" + m.getName());
m.invoke(obj, new Object[]{});
}
Field[] fs = c.getDeclaredFields();
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
System.out.println("Field:" + f.getName() + ", Modifier:" + f.getModifiers());
if((Modifier.PUBLIC+ Modifier.STATIC) == f.getModifiers()){
System.out.println("Used public and static qualify!");
}
//
f.setAccessible(true);
try {
String value = (String)f.get(obj);
System.out.println("Field " + f.getName() + " default value:" + value);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param args
*/
public static void main(String[] args) {
ClassLoaderTest ct = new ClassLoaderTest();
ct.loadTest();
}
このメソッドがクラスをマウントすると、クラスのメモリ領域がアプリケーションマウントクラスに適用されます.
2、カスタムクラスマウンタの例:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
}
else {
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] getClassData(String className) {
String path = classNameToPath(className);
try {
InputStream ins = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = ins.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String classNameToPath(String className) {
return rootDir + File.separatorChar
+ className.replace('.', File.separatorChar) + ".class";
}
}
このクラスローダがクラスをロードした後、クラスの実行空間はカスタムClassloaderの中で、2つに対して上記を使用するFileSystemClassLoader
またはURLClassloaderでは、同じクラスに対して、異なるClassloaderでは互いに隔離され、互いに干渉されない.3、カスタムクラスローダテスト
URLClassloaderを使用してマウントするには、次の手順に従います.
/**
* ,
*/
public void classLoadTest3c(){
try {
URL[] urls = new URL[]{ new File("D:\\Users\\workspace\\ClassLoadTest\\bin").toURI().toURL() };
ClassLoader clsLoader = new URLClassLoader(urls);
Class<?> c1 = clsLoader.loadClass("test.ClassLoaderTest");
Field f = c1.getDeclaredField("testVar");
Method m = c1.getMethod("showTestVar", null);
Object obj = c1.newInstance();
m.invoke(obj, new Object[]{});
f.set(obj, "The testVar's value is modified!");
m.invoke(obj, new Object[]{});
System.out.println("--------------------");
System.out.println(this.getClass().getClassLoader());
ClassLoader clsLoader2 = new URLClassLoader(urls);
System.out.println(clsLoader2.getSystemClassLoader());
Class<?> c2 = clsLoader2.loadClass("test.ClassLoaderTest");
Object obj2 = c2.newInstance();
Method m2 = c2.getMethod("showTestVar", null);
m2.invoke(obj2, new Object[]{});
m.invoke(obj, new Object[]{});
m2.invoke(obj2, new Object[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
ClassLoaderTest.JAva,参照1.
4、既存のカスタムクラスマウンタにマウントする
/**
* ,
*/
public void classLoadTest3d(){
try {
URL[] urls = new URL[]{ new File("D:\\Users\\workspace\\ClassLoadTest\\bin").toURI().toURL() };
ClassLoader clsLoader = new URLClassLoader(urls);
Class<?> c1 = clsLoader.loadClass("test.ClassLoaderTest");
Field f = c1.getDeclaredField("testVar");
Method m = c1.getMethod("showTestVar", null);
Object obj = c1.newInstance();
m.invoke(obj, new Object[]{});
f.set(obj, "The testVar's value is modified!");
m.invoke(obj, new Object[]{});
System.out.println("--------------------");
System.out.println(this.getClass().getClassLoader());
ClassLoader clsLoader2 = new URLClassLoader(urls, clsLoader);
System.out.println(clsLoader2.getSystemClassLoader());
Class<?> c2 = clsLoader2.loadClass("test.ClassLoaderTest");
Object obj2 = c2.newInstance();
Method m2 = c2.getMethod("showTestVar", null);
m2.invoke(obj2, new Object[]{});
m.invoke(obj, new Object[]{});
m2.invoke(obj2, new Object[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
clsLoader 2はclsLoaderのClassloaderを使用するため、clsLoader 2のクラス「test.ClassLoader Test」はclsLoaderの「test.ClassLoader Test」を使用する5、これらのテストのクラスは、現在のプロジェクトのクラスパスの下に置かないでください.それ以外の場合、Bootrapクラスマウンタは自動的にマウントされるため、ロードされたクラスを再ロードするのは無効です.
6、