如何裸寫或利用Spring掃描出指定包下的所有類名

在很多Java框架中都有組件掃描功能,即給出一個註解,框架能夠把所有標註了此註解的類找出來。這種操作的本質是給出一個名包,能獲取到此包下的所有類名,然後再通過反射判斷是否加了指定的註解。無論是什麼框架,包括Spring, 完成這個功能底層都是用的ClassLoader.getResources()ClassLoader.getSystemResources()方法實現的,即先找出指定classpath下的"資源",可能是文件也可能是jar包,然後通過文件I/O讀取jar, 把每一個.class文件名全部列出即可。如果我們要自己手寫這樣的功能的話就必須參照這個思路去實現,但是邏輯比較複雜,主要是很多細節問題需要注意。這裏有一個我自己實現的PkgScanner可供參考,github: https://github.com/wanghongfei/pkg-scanner

當然,多數時候我們並不想自己重複造輪子。Spring就有現成的類可以讓我們直接使用, 它們分別是ResourcePatternResolverCachingMetadataReaderFactory,使用方法如下:

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()方法中找到答案:
code
即,本質還是掃描jar包,讀取jar包。

其實這個功能最好直接集成到JDK的類庫中,這樣大家就不必繞這麼大圈子來實現這個看似簡單但邏輯又非常複雜的功能了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章