是否有可能找到给定包中的所有类或接口?(快速看了一下e.g. Package,似乎没有。)


当前回答

这将扫描类加载器和所有父加载器,以查找jar文件和目录。 jar文件和由jar的类路径引用的目录也会被加载。

this code is testet with Java 8,11,18. on 8 everything works perfectly using the URLClassLoader and the getURLs() method. on 11 it works fine using reflections, but the JVM prints a warning on the stderr stream (not redirectible with System.setErr() with my JVM) on 18 the reflections are useless (throws NoSuchMethod/Field), and the only thing (where I know that it works) is to use the getResource() method. When the class loader loades the resources of the given package from the file system a simple path url is returned. When the class loader loades the resources from a jar a url like 'jar:file:[jar-path]!/[in-jar-path]' is returned.

我使用了答案https://stackoverflow.com/a/1157352/18252455(来自一个重复的问题),并添加了读取类路径和搜索目录url的功能。

/**
 * orig description:<br>
 * Scans all classloaders for the current thread for loaded jars, and then scans
 * each jar for the package name in question, listing all classes directly under
 * the package name in question. Assumes directory structure in jar file and class
 * package naming follow java conventions (i.e. com.example.test.MyTest would be in
 * /com/example/test/MyTest.class)
 * <p>
 * in addition this method also scans for directories, where also is assumed, that the classes are
 * placed followed by the java conventions. (i.e. <code>com.example.test.MyTest</code> would be in
 * <code>directory/com/example/test/MyTest.class</code>)
 * <p>
 * this method also reads the jars Class-Path for other jars and directories. for the jars and
 * directories referred in the jars are scanned with the same rules as defined here.<br>
 * it is ensured that no jar/directory is scanned exactly one time.
 * <p>
 * if {@code bailError} is <code>true</code> all errors will be wrapped in a
 * {@link RuntimeException}
 * and then thrown.<br>
 * a {@link RuntimeException} will also be thrown if something unexpected happens.<br>
 * 
 * @param packageName
 *            the name of the package for which the classes should be searched
 * @param allowSubPackages
 *            <code>true</code> is also classes in sub packages should be found
 * @param loader
 *            the {@link ClassLoader} which should be used to find the URLs and to load classes
 * @param bailError
 *            if all {@link Exception} should be re-thrown wrapped in {@link RuntimeException} and
 *            if a {@link RuntimeException} should be thrown, when something is not as expected.
 * @see https://stackoverflow.com/questions/1156552/java-package-introspection
 * @see https://stackoverflow.com/a/1157352/18252455
 * @see https://creativecommons.org/licenses/by-sa/2.5/
 * @see https://creativecommons.org/licenses/by-sa/2.5/legalcode
 */
public static Set <Class <?>> tryGetClassesForPackage(String packageName, boolean allowSubPackages, ClassLoader loader, boolean bailError) {
    Set <URL> jarUrls = new HashSet <URL>();
    Set <Path> directorys = new HashSet <Path>();
    findClassPools(loader, jarUrls, directorys, bailError, packageName);
    Set <Class <?>> jarClasses = findJarClasses(allowSubPackages, packageName, jarUrls, directorys, loader, bailError);
    Set <Class <?>> dirClasses = findDirClasses(allowSubPackages, packageName, directorys, loader, bailError);
    jarClasses.addAll(dirClasses);
    return jarClasses;
}

private static Set <Class <?>> findDirClasses(boolean subPackages, String packageName, Set <Path> directorys, ClassLoader loader, boolean bailError) {
    Filter <Path> filter;
    Set <Class <?>> result = new HashSet <>();
    for (Path startPath : directorys) {
        String packagePath = packageName.replace(".", startPath.getFileSystem().getSeparator());
        final Path searchPath = startPath.resolve(packagePath).toAbsolutePath();
        if (subPackages) {
            filter = p -> {
                p = p.toAbsolutePath();
                Path other;
                if (p.getNameCount() >= searchPath.getNameCount()) {
                    other = searchPath;
                } else {
                    other = searchPath.subpath(0, p.getNameCount());
                }
                if (p.startsWith(other)) {
                    return true;
                } else {
                    return false;
                }
            };
        } else {
            filter = p -> {
                p = p.toAbsolutePath();
                if (p.getNameCount() > searchPath.getNameCount() + 1) {
                    return false;
                } else if (p.toAbsolutePath().startsWith(searchPath)) {
                    return true;
                } else {
                    return false;
                }
            };
        }
        if (Files.exists(searchPath)) {
            findDirClassFilesRecursive(filter, searchPath, startPath, result, loader, bailError);
        } // the package does not have to exist in every directory
    }
    return result;
}

private static void findDirClassFilesRecursive(Filter <Path> filter, Path path, Path start, Set <Class <?>> classes, ClassLoader loader, boolean bailError) {
    try (DirectoryStream <Path> dirStream = Files.newDirectoryStream(path, filter)) {
        for (Path p : dirStream) {
            if (Files.isDirectory(p)) {
                findDirClassFilesRecursive(filter, p, start, classes, loader, bailError);
            } else {
                Path subp = p.subpath(start.getNameCount(), p.getNameCount());
                String str = subp.toString();
                if (str.endsWith(".class")) {
                    str = str.substring(0, str.length() - 6);
                    String sep = p.getFileSystem().getSeparator();
                    if (str.startsWith(sep)) {
                        str = str.substring(sep.length());
                    }
                    if (str.endsWith(sep)) {
                        str = str.substring(0, str.length() - sep.length());
                    }
                    String fullClassName = str.replace(sep, ".");
                    try {
                        Class <?> cls = Class.forName(fullClassName, false, loader);
                        classes.add(cls);
                    } catch (ClassNotFoundException e) {
                        if (bailError) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }
    } catch (IOException e) {
        if (bailError) {
            throw new RuntimeException(e);
        }
    }
}

private static Set <Class <?>> findJarClasses(boolean subPackages, String packageName, Set <URL> nextJarUrls, Set <Path> directories, ClassLoader loader, boolean bailError) {
    String packagePath = packageName.replace('.', '/');
    Set <Class <?>> result = new HashSet <>();
    Set <URL> allJarUrls = new HashSet <>();
    while (true) {
        Set <URL> thisJarUrls = new HashSet <>(nextJarUrls);
        thisJarUrls.removeAll(allJarUrls);
        if (thisJarUrls.isEmpty()) {
            break;
        }
        allJarUrls.addAll(thisJarUrls);
        for (URL url : thisJarUrls) {
            try (JarInputStream stream = new JarInputStream(url.openStream())) {
                // may want better way to open url connections
                readJarClassPath(stream, nextJarUrls, directories, bailError);
                JarEntry entry = stream.getNextJarEntry();
                while (entry != null) {
                    String name = entry.getName();
                    int i = name.lastIndexOf("/");
                    
                    if (i > 0 && name.endsWith(".class")) {
                        try {
                            if (subPackages) {
                                if (name.substring(0, i).startsWith(packagePath)) {
                                    Class <?> cls = Class.forName(name.substring(0, name.length() - 6).replace("/", "."), false, loader);
                                    result.add(cls);
                                }
                            } else {
                                if (name.substring(0, i).equals(packagePath)) {
                                    Class <?> cls = Class.forName(name.substring(0, name.length() - 6).replace("/", "."), false, loader);
                                    result.add(cls);
                                }
                            }
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                    entry = stream.getNextJarEntry();
                }
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return result;
}

private static void readJarClassPath(JarInputStream stream, Set <URL> jarUrls, Set <Path> directories, boolean bailError) {
    Object classPathObj = stream.getManifest().getMainAttributes().get(new Name("Class-Path"));
    if (classPathObj == null) {
        return;
    }
    if (classPathObj instanceof String) {
        String[] entries = ((String) classPathObj).split("\\s+");// should also work with a single space (" ")
        for (String entry : entries) {
            try {
                URL url = new URL(entry);
                addFromUrl(jarUrls, directories, url, bailError);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
    } else if (bailError) {
        throw new RuntimeException("the Class-Path attribute is no String: " + classPathObj.getClass().getName() + " tos='" + classPathObj + "'");
    }
}

private static void findClassPools(ClassLoader classLoader, Set <URL> jarUrls, Set <Path> directoryPaths, boolean bailError, String packageName) {
    packageName = packageName.replace('.', '/');
    while (classLoader != null) {
        if (classLoader instanceof URLClassLoader) {
            for (URL url : ((URLClassLoader) classLoader).getURLs()) {
                addFromUrl(jarUrls, directoryPaths, url, bailError);
                System.out.println("rurl-class-loade.url[n]r->'" + url + "'");
            }
        } else {
            URL res = classLoader.getResource("");
            if (res != null) {
                addFromUrl(jarUrls, directoryPaths, res, bailError);
            }
            res = classLoader.getResource("/");
            if (res != null) {
                addFromUrl(jarUrls, directoryPaths, res, bailError);
            }
            res = classLoader.getResource("/" + packageName);
            if (res != null) {
                res = removePackageFromUrl(res, packageName, bailError);
                if (res != null) {
                    addFromUrl(jarUrls, directoryPaths, res, bailError);
                }
            }
            res = classLoader.getResource(packageName);
            if (res != null) {
                res = removePackageFromUrl(res, packageName, bailError);
                if (res != null) {
                    addFromUrl(jarUrls, directoryPaths, res, bailError);
                }
            }
            addFromUnknownClass(classLoader, jarUrls, directoryPaths, bailError, 8);
        }
        classLoader = classLoader.getParent();
    }
}

private static URL removePackageFromUrl(URL res, String packagePath, boolean bailError) {
    packagePath = "/" + packagePath;
    String urlStr = res.toString();
    if ( !urlStr.endsWith(packagePath)) {
        if (bailError) {
            throw new RuntimeException("the url string does not end with the packagepath! packagePath='" + packagePath + "' urlStr='" + urlStr + "'");
        } else {
            return null;
        }
    }
    urlStr = urlStr.substring(0, urlStr.length() - packagePath.length());
    if (urlStr.endsWith("!")) {
        urlStr = urlStr.substring(0, urlStr.length() - 1);
    }
    if (urlStr.startsWith("jar:")) {
        urlStr = urlStr.substring(4);
    }
    try {
        return new URL(urlStr);
    } catch (MalformedURLException e) {
        if (bailError) {
            throw new RuntimeException(e);
        } else {
            return null;
        }
    }
}

private static void addFromUnknownClass(Object instance, Set <URL> jarUrls, Set <Path> directoryPaths, boolean bailError, int maxDeep) {
    Class <?> cls = instance.getClass();
    while (cls != null) {
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            Class <?> type = field.getType();
            Object value;
            try {
                value = getValue(instance, field);
                if (value != null) {
                    addFromUnknownValue(value, jarUrls, directoryPaths, bailError, type, field.getName(), maxDeep - 1);
                }
            } catch (IllegalArgumentException | IllegalAccessException | SecurityException e) {
                if (bailError) {
                    final String version = System.getProperty("java.version");
                    String vers = version;
                    if (vers.startsWith("1.")) {
                        vers = vers.substring(2);
                    }
                    int dotindex = vers.indexOf('.');
                    if (dotindex != -1) {
                        vers = vers.substring(0, dotindex);
                    }
                    int versNum;
                    try {
                        versNum = Integer.parseInt(vers);
                    } catch (NumberFormatException e1) {
                        throw new RuntimeException("illegal version: '" + version + "' lastError: " + e.getMessage(), e);
                    }
                    if (versNum <= 11) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        cls = cls.getSuperclass();
    }
    
}

private static Object getValue(Object instance, Field field) throws IllegalArgumentException, IllegalAccessException, SecurityException {
    try {
        boolean flag = field.isAccessible();
        boolean newflag = flag;
        try {
            field.setAccessible(true);
            newflag = true;
        } catch (Exception e) {}
        try {
            return field.get(instance);
        } finally {
            if (flag != newflag) {
                field.setAccessible(flag);
            }
        }
    } catch (IllegalArgumentException | IllegalAccessException | SecurityException e) {
        try {
            Field override = AccessibleObject.class.getDeclaredField("override");
            boolean flag = override.isAccessible();
            boolean newFlag = flag;
            try {
                override.setAccessible(true);
                flag = true;
            } catch (Exception s) {}
            override.setBoolean(field, true);
            if (flag != newFlag) {
                override.setAccessible(flag);
            }
            return field.get(instance);
        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e1) {
            e.addSuppressed(e1);
            throw e;
        }
    }
}

private static void addFromUnknownValue(Object value, Set <URL> jarUrls, Set <Path> directoryPaths, boolean bailError, Class <?> type, String fieldName, int maxDeep) {
    if (Collection.class.isAssignableFrom(type)) {
        for (Object obj : (Collection <?>) value) {
            URL url = null;
            try {
                if (obj instanceof URL) {
                    url = (URL) obj;
                } else if (obj instanceof Path) {
                    url = ((Path) obj).toUri().toURL();
                } else if (obj instanceof File) {
                    url = ((File) obj).toURI().toURL();
                }
            } catch (MalformedURLException e) {
                if (bailError) {
                    throw new RuntimeException(e);
                }
            }
            if (url != null) {
                addFromUrl(jarUrls, directoryPaths, url, bailError);
            }
        }
    } else if (URL[].class.isAssignableFrom(type)) {
        for (URL url : (URL[]) value) {
            addFromUrl(jarUrls, directoryPaths, url, bailError);
        }
    } else if (Path[].class.isAssignableFrom(type)) {
        for (Path path : (Path[]) value) {
            try {
                addFromUrl(jarUrls, directoryPaths, path.toUri().toURL(), bailError);
            } catch (MalformedURLException e) {
                if (bailError) {
                    throw new RuntimeException(e);
                }
            }
        }
    } else if (File[].class.isAssignableFrom(type)) {
        for (File file : (File[]) value) {
            try {
                addFromUrl(jarUrls, directoryPaths, file.toURI().toURL(), bailError);
            } catch (MalformedURLException e) {
                if (bailError) {
                    throw new RuntimeException(e);
                }
            }
        }
    } else if (maxDeep > 0) {
        addFromUnknownClass(value, jarUrls, directoryPaths, bailError, maxDeep - 1);
    }
}

private static void addFromUrl(Set <URL> jarUrls, Set <Path> directoryPaths, URL url, boolean bailError) {
    if (url.getFile().endsWith(".jar") || url.getFile().endsWith(".zip")) {
        // may want better way to detect jar files
        jarUrls.add(url);
    } else {
        try {
            Path path = Paths.get(url.toURI());
            if (Files.isDirectory(path)) {
                directoryPaths.add(path);
            } else if (bailError) {
                throw new RuntimeException("unknown url for class loading: " + url);
            }
        } catch (URISyntaxException e) {
            if (bailError) {
                throw new RuntimeException(e);
            }
        }
    }
}

进口:

import java.io.File;
import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.DirectoryStream;
import java.nio.file.DirectoryStream.Filter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.Attributes.Name;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

其他回答

我刚写了一个util类,里面包含了测试方法,大家可以检查一下~

IteratePackageUtil.java:

package eric.j2se.reflect;

import java.util.Set;

import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

/**
 * an util to iterate class in a package,
 * 
 * @author eric
 * @date Dec 10, 2013 12:36:46 AM
 */
public class IteratePackageUtil {
    /**
     * <p>
     * Get set of all class in a specified package recursively. this only support lib
     * </p>
     * <p>
     * class of sub package will be included, inner class will be included,
     * </p>
     * <p>
     * could load class that use the same classloader of current class, can't load system packages,
     * </p>
     * 
     * @param pkg
     *            path of a package
     * @return
     */
    public static Set<Class<? extends Object>> getClazzSet(String pkg) {
        // prepare reflection, include direct subclass of Object.class
        Reflections reflections = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner(false), new ResourcesScanner())
                .setUrls(ClasspathHelper.forClassLoader(ClasspathHelper.classLoaders(new ClassLoader[0])))
                .filterInputsBy(new FilterBuilder().includePackage(pkg)));

        return reflections.getSubTypesOf(Object.class);
    }

    public static void test() {
        String pkg = "org.apache.tomcat.util";

        Set<Class<? extends Object>> clazzSet = getClazzSet(pkg);
        for (Class<? extends Object> clazz : clazzSet) {
            System.out.println(clazz.getName());
        }
    }

    public static void main(String[] args) {
        test();
    }
}

你好。我总是对上面的解决方案(以及其他网站上的)有一些问题。 我,作为一名开发人员,正在为API编程一个插件。该API防止使用任何外部库或第三方工具。设置还包括jar或zip文件中的代码和直接位于某些目录中的类文件。所以我的代码必须能够解决每一个设置。经过大量的研究,我想出了一个方法,可以在所有可能的设置中至少95%的情况下工作。

下面的代码基本上是总是有效的overkill方法。

代码:

这段代码扫描给定包中包含的所有类。它只对当前ClassLoader中的所有类有效。

/**
 * Private helper method
 * 
 * @param directory
 *            The directory to start with
 * @param pckgname
 *            The package name to search for. Will be needed for getting the
 *            Class object.
 * @param classes
 *            if a file isn't loaded but still is in the directory
 * @throws ClassNotFoundException
 */
private static void checkDirectory(File directory, String pckgname,
        ArrayList<Class<?>> classes) throws ClassNotFoundException {
    File tmpDirectory;

    if (directory.exists() && directory.isDirectory()) {
        final String[] files = directory.list();

        for (final String file : files) {
            if (file.endsWith(".class")) {
                try {
                    classes.add(Class.forName(pckgname + '.'
                            + file.substring(0, file.length() - 6)));
                } catch (final NoClassDefFoundError e) {
                    // do nothing. this class hasn't been found by the
                    // loader, and we don't care.
                }
            } else if ((tmpDirectory = new File(directory, file))
                    .isDirectory()) {
                checkDirectory(tmpDirectory, pckgname + "." + file, classes);
            }
        }
    }
}

/**
 * Private helper method.
 * 
 * @param connection
 *            the connection to the jar
 * @param pckgname
 *            the package name to search for
 * @param classes
 *            the current ArrayList of all classes. This method will simply
 *            add new classes.
 * @throws ClassNotFoundException
 *             if a file isn't loaded but still is in the jar file
 * @throws IOException
 *             if it can't correctly read from the jar file.
 */
private static void checkJarFile(JarURLConnection connection,
        String pckgname, ArrayList<Class<?>> classes)
        throws ClassNotFoundException, IOException {
    final JarFile jarFile = connection.getJarFile();
    final Enumeration<JarEntry> entries = jarFile.entries();
    String name;

    for (JarEntry jarEntry = null; entries.hasMoreElements()
            && ((jarEntry = entries.nextElement()) != null);) {
        name = jarEntry.getName();

        if (name.contains(".class")) {
            name = name.substring(0, name.length() - 6).replace('/', '.');

            if (name.contains(pckgname)) {
                classes.add(Class.forName(name));
            }
        }
    }
}

/**
 * Attempts to list all the classes in the specified package as determined
 * by the context class loader
 * 
 * @param pckgname
 *            the package name to search
 * @return a list of classes that exist within that package
 * @throws ClassNotFoundException
 *             if something went wrong
 */
public static ArrayList<Class<?>> getClassesForPackage(String pckgname)
        throws ClassNotFoundException {
    final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();

    try {
        final ClassLoader cld = Thread.currentThread()
                .getContextClassLoader();

        if (cld == null)
            throw new ClassNotFoundException("Can't get class loader.");

        final Enumeration<URL> resources = cld.getResources(pckgname
                .replace('.', '/'));
        URLConnection connection;

        for (URL url = null; resources.hasMoreElements()
                && ((url = resources.nextElement()) != null);) {
            try {
                connection = url.openConnection();

                if (connection instanceof JarURLConnection) {
                    checkJarFile((JarURLConnection) connection, pckgname,
                            classes);
                } else if (connection instanceof FileURLConnection) {
                    try {
                        checkDirectory(
                                new File(URLDecoder.decode(url.getPath(),
                                        "UTF-8")), pckgname, classes);
                    } catch (final UnsupportedEncodingException ex) {
                        throw new ClassNotFoundException(
                                pckgname
                                        + " does not appear to be a valid package (Unsupported encoding)",
                                ex);
                    }
                } else
                    throw new ClassNotFoundException(pckgname + " ("
                            + url.getPath()
                            + ") does not appear to be a valid package");
            } catch (final IOException ioex) {
                throw new ClassNotFoundException(
                        "IOException was thrown when trying to get all resources for "
                                + pckgname, ioex);
            }
        }
    } catch (final NullPointerException ex) {
        throw new ClassNotFoundException(
                pckgname
                        + " does not appear to be a valid package (Null pointer exception)",
                ex);
    } catch (final IOException ioex) {
        throw new ClassNotFoundException(
                "IOException was thrown when trying to get all resources for "
                        + pckgname, ioex);
    }

    return classes;
}

这三个方法使您能够查找给定包中的所有类。 你可以这样使用它:

getClassesForPackage("package.your.classes.are.in");

解释:

该方法首先获取当前的ClassLoader。然后,它获取包含该包的所有资源,并迭代这些url。然后它创建一个URLConnection并确定我们拥有的URl类型。它可以是一个目录(FileURLConnection),也可以是一个jar或zip文件中的目录(JarURLConnection)。根据我们所拥有的连接类型,将调用两个不同的方法。

首先让我们看看如果它是一个FileURLConnection会发生什么。 它首先检查传递的File是否存在,是否为目录。如果是这样,它会检查它是否是类文件。如果是这样,一个Class对象将被创建并放入数组列表中。如果它不是一个类文件,而是一个目录,我们只需迭代它,并做同样的事情。所有其他案例/文件将被忽略。

如果URLConnection是JarURLConnection,另一个私有助手方法将被调用。此方法迭代zip/jar存档中的所有条目。如果一个条目是一个类文件,并且在包内部,一个class对象将被创建并存储在ArrayList中。

在所有资源被解析后,它(main方法)返回包含给定包中当前ClassLoader所知道的所有类的ArrayList。

如果进程在任何时候失败,将抛出一个ClassNotFoundException,其中包含关于确切原因的详细信息。

这是不可能的,因为包中的所有类都可能不会被加载,而你总是知道一个类的包。

我是这样做的。我扫描所有的子文件夹(子包),我不尝试加载匿名类:

   /**
   * Attempts to list all the classes in the specified package as determined
   * by the context class loader, recursively, avoiding anonymous classes
   * 
   * @param pckgname
   *            the package name to search
   * @return a list of classes that exist within that package
   * @throws ClassNotFoundException
   *             if something went wrong
   */
  private static List<Class> getClassesForPackage(String pckgname) throws ClassNotFoundException {
      // This will hold a list of directories matching the pckgname. There may be more than one if a package is split over multiple jars/paths
      ArrayList<File> directories = new ArrayList<File>();
      String packageToPath = pckgname.replace('.', '/');
      try {
          ClassLoader cld = Thread.currentThread().getContextClassLoader();
          if (cld == null) {
              throw new ClassNotFoundException("Can't get class loader.");
          }

          // Ask for all resources for the packageToPath
          Enumeration<URL> resources = cld.getResources(packageToPath);
          while (resources.hasMoreElements()) {
              directories.add(new File(URLDecoder.decode(resources.nextElement().getPath(), "UTF-8")));
          }
      } catch (NullPointerException x) {
          throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Null pointer exception)");
      } catch (UnsupportedEncodingException encex) {
          throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Unsupported encoding)");
      } catch (IOException ioex) {
          throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + pckgname);
      }

      ArrayList<Class> classes = new ArrayList<Class>();
      // For every directoryFile identified capture all the .class files
      while (!directories.isEmpty()){
          File directoryFile  = directories.remove(0);             
          if (directoryFile.exists()) {
              // Get the list of the files contained in the package
              File[] files = directoryFile.listFiles();

              for (File file : files) {
                  // we are only interested in .class files
                  if ((file.getName().endsWith(".class")) && (!file.getName().contains("$"))) {
                      // removes the .class extension
                      int index = directoryFile.getPath().indexOf(packageToPath);
                      String packagePrefix = directoryFile.getPath().substring(index).replace('/', '.');;                          
                    try {                  
                      String className = packagePrefix + '.' + file.getName().substring(0, file.getName().length() - 6);                            
                      classes.add(Class.forName(className));                                
                    } catch (NoClassDefFoundError e)
                    {
                      // do nothing. this class hasn't been found by the loader, and we don't care.
                    }
                  } else if (file.isDirectory()){ // If we got to a subdirectory
                      directories.add(new File(file.getPath()));                          
                  }
              }
          } else {
              throw new ClassNotFoundException(pckgname + " (" + directoryFile.getPath() + ") does not appear to be a valid package");
          }
      }
      return classes;
  }  

如果您只是想加载一组相关的类,那么Spring可以帮助您。

Spring可以在一行代码中实例化实现给定接口的所有类的列表或映射。列表或映射将包含实现该接口的所有类的实例。

也就是说,作为从文件系统中加载类列表的替代方法,只需在您想要加载的所有类中实现相同的接口,而不管包是什么,并使用Spring为您提供所有这些类的实例。这样,您就可以加载(并实例化)您想要的所有类,而不管它们在哪个包中。

另一方面,如果您希望将它们都放在一个包中,那么只需让包中的所有类实现给定的接口。

注意,接口本身不需要声明任何方法——它可以完全为空。

要注入实现给定接口的类列表,请使用以下代码行…

  @Autowired
  private List<ISomeInterface> implementationList;

也可以使用Spring注入类的Map。如果有兴趣,请阅读文档。

最后,我将提供一个比搜索整个文件系统树更优雅的解决方案。

创建一个自定义注释,用于构建应用于它的类的目录——类似于@ClassCatalog。