我们在使用Spring时可以指定一个名包,Spring可以自动扫描出该包下的所有组件。通过翻阅Spring源码,其实这个功能不难实现。
首先,所有在classpath下的资源(文件),都是可以被ClassLoader
加载的。我们可以调用它的getResources()
方法加载类路径下的文件:
public Enumeration<URL> getResources(String name)
throws IOException
这个方法返回一个Enumeration
对象,以URL
对象的形式保存了路径name
下的所有资源。 如果我们传递一个包路径cn/fh
, :
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Enumeration<URL> 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
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-07 00:59:39