Java类自动扫描功能的实现

我们在使用Spring时可以指定一个名包,Spring可以自动扫描出该包下的所有组件。通过翻阅Spring源码,其实这个功能不难实现。

首先,所有在classpath下的资源(文件),都是可以被ClassLoader加载的。我们可以调用它的getResources()方法加载类路径下的文件:

public Enumeration getResources(String name)
                              throws IOException

这个方法返回一个Enumeration对象,以URL对象的形式保存了路径name下的所有资源。 如果我们传递一个包路径cn/fh, :

ClassLoader cl = Thread.currentThread().getContextClassLoader();

        Enumeration urls = cl.getResources("cn/fh");
        while (urls.hasMoreElements()) {
            URL u = urls.nextElement();
            System.out.println(u);
            System.out.println(u.getProtocol());
            System.out.println(u.getPath());
        }

则有以下输出结果:

file:/Users/whf/projects/exam/out/production/exam/cn/fh/
file
/Users/whf/projects/exam/out/production/exam/cn/fh/

这是cn/fh不在JAR包中的结果。如果是在JAR包中,则输出以下信息:

jar:file:/Users/whf/.m2/repository/cn/fh/web-security/2.1.1.RELEASE/web-security-2.1.1.RELEASE.jar!/cn/fh/
jar
file:/Users/whf/.m2/repository/cn/fh/web-security/2.1.1.RELEASE/web-security-2.1.1.RELEASE.jar!/cn/fh/

由此, 我们可以得出扫描功能的思路:
1. 调用ClassLoader#getResources()方法,得到返回的URL集合
2. 遍历所有URL对象。
3. 如果是文件,则通过文件I/O操作遍历该目录下所有*.class文件,提取出类名。
4. 如果是Jar包,则通过Jar包I/O操作遍历该Jar包,提取出包中所有*.class文件。

根据以上思路,我们可以写一个PkgScanner类,并提供以下使用方法:

PkgScanner scanner = new PkgScanner("cn.fh.pkgscanner");
    List<String> list = scanner.scan();

    list.forEach( f -> System.out.println(f));

输出:

cn.fh.pkgscanner.PathUtils
cn.fh.pkgscanner.PkgScanner
cn.fh.pkgscanner.ResourceType

完整的实现在github:https://github.com/wanghongfei/pkg-scanner

你可能感兴趣的:(Java)