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

Sve*_*ven 15 java reloading

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

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

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

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

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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

List<Request> requests = new ArrayList<Request>();
    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();
            }
Run Code Online (Sandbox Code Playgroud)

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

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

Hol*_*ger 10

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

最简单的解决方案是设置正确的父类加载器.您正在传递Thread.currentThread().getContextClassLoader()这是一个有点奇怪作为你的主要目的是,代表团应该不会委托给该加载器,但加载变更类.您必须考虑哪些类加载器存在以及使用哪些类加载器.例如,如果该类Foo在您当前代码的范围内,但您希望(重新)使用新的ClassLoader加载它,Foo.class.getClassLoader().getParent()那么它将是新的Class的父代表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));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)