1

我像疯了一样做了两个小时的stackoverflow,但到目前为止没有任何帮助。

我有一个非常基本的 Maven 项目,其中有一些 Singleton 类。据说可以使用不同的类加载器加载单例两次,所以我编写了自己的,但问题是我无法加载该类,因为我得到 ClassNotFoundException 但我不知道为什么。

@RunWith(JUnit4.class)
public class SingletonClassLoadedDifferentClassLoadersTestCase {

    static class SingletonClassLoader extends ClassLoader {

        @Override
        public Class<?> loadClass(String className)
          throws ClassNotFoundException {
            try {
                InputStream is =
                    // seems to be the central problem 
                    ClassLoader.getSystemResourceAsStream(className);
                if (is == null) {
                    throw new ClassNotFoundException();
                }

                ByteArrayOutputStream buffer = new ByteArrayOutputStream();

                int nRead;
                byte[] data = new byte[1024];

                while ((nRead = is.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }

                byte[] classBytes = buffer.toByteArray();

                return defineClass(className, classBytes, 0, classBytes.length);
            } catch (IOException ex) {
                throw new ClassNotFoundException();
            }
        }
    }

    @Test
    public void singletonTest() throws Exception {
        Class<?> singleton1 = new SingletonClassLoader()
            .loadClass("SingletonLazy");
        Class<?> singleton2 = new SingletonClassLoader()
            .loadClass("SingletonLazy");
    }
}

SingletonLazy只是 src/main/java 中的一个类(埋在某个包目录中)。似乎 ClassLoader 无法找到该类,但为什么呢?我看到它不在. target/test-classes在我进行测试时,如何告诉 Maven 以某种方式将该类放在类路径上的 src/main/java/some/package/SingletonLazy.java 中?我正在从命令行执行它mvn clean test

谢谢你的任何提示!

4

1 回答 1

0

不要使用 SystemClassLoader。请改用直接类加载器。将您的代码更改为,

InputStream is = SingletonClassLoadedDifferentClassLoadersTestCase.class
      .getClassLoader()
      .getResourceAsStream(className);

我相信 JUnit 会为每个测试创建一个单独的类加载器。我的印象是 JUnit 这样做是为了避免静态状态造成的问题。我尝试了一些测试,我可以看到情况并非如此!即使您有一个在src/test/java其静态状态下定义的类也不会被擦除,也就是说每个测试都不会重新加载类。

我尝试的第二件事是 fork 测试,但<forkMode>always</forkMode>我相信最高级别的 fork 仅适用于在两个不同测试类中定义的测试。如果您在同一个类中定义了测试方法,那么所有运行的测试方法都将使用同一个 JVM 实例。

静力学本质上是不好的,所以我建议使用控制反转 (IOC) 框架。我过去使用过 Guice,它非常轻量级和高效。

于 2013-07-12T05:25:02.350 回答