Class 類載入器,內部類載入實驗
阿新 • • 發佈:2018-12-26
最近實驗通過jdk編譯後的Class多出一個內部類class檔案,美元$符號的class檔案,如A.class ,A$B.class,載入A.class總是報錯。
除了載入內部類方法,還有就是把class檔案打包成jar,通過自定義URLClassLoader 載入jar檔案,做類似與Osgi的工作。
通過類載入器,做一個動態載入模組的應用伺服器。
通過網上找到程式碼例子改改後解決現在的問題。
Exception in thread "main" java.lang.LinkageError: loader constraint violation: when resolving method "com.lw.loader.TestClass$TestInnerClass.<init>(Lcom/lw/loader/TestClass;)V" the class loader (instance of com/lw/loader/DynamicClassLoader) of the current class, com/lw/loader/TestClass, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for resolved class, com/lw/loader/TestClass$TestInnerClass, have different Class objects for the type tClass;)V used in the signature at com.lw.loader.TestClass.<init>(TestClass.java:12) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:526) at java.lang.Class.newInstance(Class.java:374) at com.lw.loader.DynamicClassLoaderTest.main(DynamicClassLoaderTest.java:17)
類載入器 重寫findClass,通過defineClass寫入二進位制定義Class類
ClassInfo 資訊package com.lw.loader; import java.io.File; import java.io.FileInputStream; import java.util.Hashtable; import java.util.jar.Manifest; public class DynamicClassLoader extends ClassLoader { private Manifest manifest; private Hashtable<String, ClassInfo> classInfo = new Hashtable<String, ClassInfo>(); /** * Provide delegation constructor */ DynamicClassLoader(ClassLoader parent) { super(parent); } /** * Same old ClassLoader constructor */ DynamicClassLoader() { super(); } private String getClassPath(String className) { String relativeClassPath = className.replace('.', File.separatorChar) + ".class"; String classPath; try { classPath = ClassLoader.getSystemResource(relativeClassPath).toURI().getPath().substring(1); System.out.println(classPath); if ((new File(classPath)).exists()) return classPath; } catch (java.net.URISyntaxException e) { } return null; } /** * This is the method where the task of class loading is delegated to our custom loader. * * @param name the name of the class * @return the resulting <code>Class</code> object * @exception ClassNotFoundException if the class could not be found */ protected Class findClass(String name) throws ClassNotFoundException { // get path of given class String classPath = getClassPath(name); if (classPath == null) throw new ClassNotFoundException(name); // get last modified time of class file File f = new File(classPath); long lastModified = f.lastModified(); // check if given class loaded already ClassInfo loadedClassInfo = classInfo.get(name); // if class loaded is the newest one, no need to reload it if ((loadedClassInfo != null) && (loadedClassInfo.lastModified >= lastModified)) return loadedClassInfo.classType; FileInputStream fi = null; try { fi = new FileInputStream(f); byte[] classBytes = new byte[fi.available()]; fi.read(classBytes); Class result = defineClass(name, classBytes, 0, classBytes.length); classInfo.put(name, new ClassInfo(result, lastModified)); return result; } catch (Exception e) { // We could not find the class, so indicate the problem with an exception e.printStackTrace(); throw new ClassNotFoundException(name); } finally { if (null != fi) { try { fi.close(); } catch (Exception e) { } } } } }
package com.lw.loader; public class ClassInfo { public Class classType; public long lastModified; public ClassInfo(Class classType) { this.classType = classType; this.lastModified = -1; } public ClassInfo(Class classType, long lastModified) { this.classType = classType; this.lastModified = lastModified; } }
測試類
package com.lw.loader;
public class TestClass {
public class TestInnerClass {
public void printMessage() {
System.out.println("Test inner info");
}
}
public TestClass() {
TestInnerClass cls = new TestInnerClass();
}
public void printMessage() {
System.out.println("Test info changed");
}
}
測試方法
package com.lw.loader;
import java.lang.reflect.Method;
public class DynamicClassLoaderTest {
public static void main(String[] args) throws Exception {
while (true) {
DynamicClassLoader classLoader = new DynamicClassLoader();
// classLoader.findClass("com.lw.loader.TestClass$TestInnerClass");
Class c = classLoader.findClass("com.lw.loader.TestClass");
Method printMessage = c.getMethod("printMessage");
Object o = c.newInstance();
printMessage.invoke(o);
Thread.sleep(5000);
}
}
}