如何裸写或利用Spring扫描出指定包下的所有类名
2018-09-30 本文已影响54人
司青玄
在很多Java框架中都有组件扫描功能,即给出一个注解,框架能够把所有标注了此注解的类找出来。这种操作的本质是给出一个名包,能获取到此包下的所有类名,然后再通过反射判断是否加了指定的注解。无论是什么框架,包括Spring, 完成这个功能底层都是用的ClassLoader.getResources()
或ClassLoader.getSystemResources()
方法实现的,即先找出指定classpath下的"资源",可能是文件也可能是jar包,然后通过文件I/O读取jar, 把每一个.class
文件名全部列出即可。如果我们要自己手写这样的功能的话就必须参照这个思路去实现,但是逻辑比较复杂,主要是很多细节问题需要注意。这里有一个我自己实现的PkgScanner
可供参考,github: https://github.com/wanghongfei/pkg-scanner
当然,多数时候我们并不想自己重复造轮子。Spring就有现成的类可以让我们直接使用, 它们分别是ResourcePatternResolver
和CachingMetadataReaderFactory
,使用方法如下:
public class ScanTest extends BaseTestClass implements ResourceLoaderAware {
/**
* Spring容器注入
*/
private ResourceLoader resourceLoader;
@Test
public void test() throws IOException {
ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
MetadataReaderFactory metaReader = new CachingMetadataReaderFactory(resourceLoader);
Resource[] resources = resolver.getResources("classpath*:your/package/name/**/*.class");
for (Resource r : resources) {
MetadataReader reader = metaReader.getMetadataReader(r);
System.out.println(reader.getClassMetadata().getClassName());
}
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
在我的项目里,这个单测的输出是:
output
可见已经完全满足了要求。
如果去深究源码实现,最终你会在PathMatchingResourcePatternResolver
类的doFindAllClassPathResources()
方法中找到答案:
即,本质还是扫描jar包,读取jar包。
其实这个功能最好直接集成到JDK的类库中,这样大家就不必绕这么大圈子来实现这个看似简单但逻辑又非常复杂的功能了。