在运行时Java重新加载使用的类

我正在研究一个监视目录的程序,当它看到目录中的更改时,运行目录中的所有测试。

这要求程序动态加载类,而不是获取缓存副本。

我可以动态加载测试类。 在运行时检测并使用对测试的更改。 但是,测试所测试的类不是这种情况。

我的代码用于动态加载类并返回测试类列表:

List<Class> classes = new ArrayList<Class>(); for (File file : classFiles) { String fullName = file.getPath(); String name = fullName.substring(fullName.indexOf("bin")+4) .replace('/', '.') .replace('\\', '.'); name = name.substring(0, name.length() - 6); tempClass = new DynamicClassLoader(Thread.currentThread().getContextClassLoader()).findClass(name) } catch (ClassNotFoundException e1) { // TODO Decide how to handle exception e1.printStackTrace(); } boolean cHasTestMethods = false; for(Method method: tempClass.getMethods()){ if(method.isAnnotationPresent(Test.class)){ cHasTestMethods = true; break; } } if (!Modifier.isAbstract(cachedClass.getModifiers()) && cHasTestMethods) { classes.add(tempClass); } } return classes; 

使用DynamicClassLoader作为此处描述的重载器如何强制Java在实例化时重新加载类?

知道怎么解决吗? 我以为所有类都会动态加载。 但请注意,我不会覆盖DynamicClassLoader中的loadclass,因为如果我执行测试类,则给出init

编辑:这不起作用,类被加载但其中的测试未被检测到…

 List requests = new ArrayList(); for (File file : classFiles) { String fullName = file.getPath(); String name = fullName.substring(fullName.indexOf("bin")+4) .replace('/', '.') .replace('\\', '.'); name = name.substring(0, name.length() - 6); Class cachedClass = null; Class dynamicClass = null; try { cachedClass = Class.forName(name); URL[] urls={ cachedClass.getProtectionDomain().getCodeSource().getLocation() }; ClassLoader delegateParent = cachedClass .getClassLoader().getParent(); URLClassLoader cl = new URLClassLoader(urls, delegateParent) ; dynamicClass = cl.loadClass(name); System.out.println(dynamicClass); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } 

编辑编辑:我检测到这样的测试方法:

  for(Method method: dynamicClass.getMethods()){ if(method.isAnnotationPresent(Test.class)){ requests.add(Request.method(dynamicClass, method.getName())); } } 

如果您使用自定义ClassLoader与链接答案完全相同,则不会覆盖方法protected Class loadClass(String name, boolean resolve) 。 这意味着当JVM解析依赖关系时,它仍将委托给父类加载器。 当然,当它没有委托给父ClassLoader它有可能错过一些必需的类。

最简单的解决方案是设置正确的父类加载器。 您当前正在传递Thread.currentThread().getContextClassLoader() ,这有点奇怪,因为您的主要意图是委托不应委托给该加载器,而是加载更改的类。 您必须考虑哪些类加载器存在以及使用哪些类加载器,哪些不存在。 例如,如果类Foo在您当前代码的范围内,但您希望(重新)使用新的ClassLoader加载它,则Foo.class.getClassLoader().getParent()将成为新ClassLoader的正确委托父级。 请注意,它可能为null但这并不重要,因为在这种情况下它将使用引导加载程序,然后是正确的父级。

请注意,当您设置与您的意图相匹配的右父ClassLoader您不再需要该自定义ClassLoader 。 默认实现(请参阅URLClassLoader )已经做了正确的事情。 对于当前的Java版本,它是Closeable ,使其更适合动态加载方案。

这是一个类重新加载的简单示例:

 import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; public class ReloadMyClass { public static void main(String[] args) throws ClassNotFoundException, IOException { Class myClass=ReloadMyClass.class; System.out.printf("my class is Class@%x%n", myClass.hashCode()); System.out.println("reloading"); URL[] urls={ myClass.getProtectionDomain().getCodeSource().getLocation() }; ClassLoader delegateParent = myClass.getClassLoader().getParent(); try(URLClassLoader cl=new URLClassLoader(urls, delegateParent)) { Class reloaded=cl.loadClass(myClass.getName()); System.out.printf("reloaded my class: Class@%x%n", reloaded.hashCode()); System.out.println("Different classes: "+(myClass!=reloaded)); } } }