在运行时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)); } } }
- 为什么在Spring 3.1和hibernate 4中找到当前线程exception的No Session
- 使用自定义转换器时JSFvalidation错误
- 使用按钮在打印机中打印jLabel的图标
- 寻找项目建议。 解析逻辑表达式
- 从Windows下的ANT脚本创建RPM包
- 无法使用Tomcat服务器从IntelliJ中运行/调试jsp页面
- Eclipse存储Tomcat的servlet文件在哪里?
- java.lang.UnsupportedClassVersionError:.class文件中的错误版本号
- ClassLoaders.callStaticFunction Java Eclipse的InvocationTargetException