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

code
即,本質還是掃描jar包,讀取jar包。
其實這個功能最好直接整合到JDK的類庫中,這樣大家就不必繞這麼大圈子來實現這個看似簡單但邏輯又非常複雜的功能了。