最近在學習java的反射和注解,實際情景中需要掃描某個包下的所有java類,然后使用類加載器加載類。
基本思路,獲得程序的路徑掃描src下某個包內的子包和java類,實現也比較簡單。
運行環境:windows10+jdk1.8+eclipse
直接貼代碼
package org.test.scanner; import java.io.File; import java.util.ArrayList; import java.util.List; /* * date:2019-07-23 * */ public class PackageScanner { private List<Class<?>> classes; private String packagePath = null; /* * 無參構造方法,內部調用帶參的構造方法。 * * @throw classNotFound * */ public PackageScanner() throws ClassNotFoundException { this(""); } /* * 實現,調用fileScanner進行目錄掃描和加載 * * @param String 傳入需要掃描的包 * * @throw classNotFound */ public PackageScanner(String basePackage) throws ClassNotFoundException { packagePath = System.getProperty("user.dir") + "\\src\\"; String filePath = packagePath + basePackage.replace('.', '\\'); classes = new ArrayList<Class<?>>(); fileScanner(new File(filePath)); } private void fileScanner(File file) throws ClassNotFoundException { if (file.isFile() && file.getName().lastIndexOf(".java") == file.getName().length() - 5) {//5是".java"的長度 String filePath = file.getAbsolutePath(); String qualifiedName = filePath.substring(packagePath.length(), filePath.length() - 5).replace('\\', '.'); System.out.println(qualifiedName); classes.add(Class.forName(qualifiedName)); return; } else if (file.isDirectory()) { for (File f : file.listFiles()) fileScanner(f); } } /* * 得到加載到的類對象的List,返回的是ArrayList */ public List<Class<?>> getClasses() { return this.classes; } }
這是一個簡單的包掃描類,這里直接使用Class.forName()加載掃描到的類
我們可以看一下forName實現
public static Class<?> forName(String className) throws ClassNotFoundException { return forName0(className, true, ClassLoader.getCallerClassLoader()); }
發現調用了ClassLoader.getCallerClassLoader()
從名字上可以看出是得到調用類的類加載器,我們可以看一下它的實現
static ClassLoader getCallerClassLoader() { // NOTE use of more generic Reflection.getCallerClass() Class caller = Reflection.getCallerClass(3); // This can be null if the VM is requesting it if (caller == null) { return null; } return caller.getClassLoader0(); }
關鍵一句: Reflection.getCallerClass(3)。
一直往上傳遞,直到獲取到它的調用類,然后得到調用類的類加載器
其中 REflection.getCallerClass()的參數有:
0 和小於0 - 返回 Reflection類
1 - 返回自己的類
2 - 返回調用者的類
3. 4. ....層層上傳。
最后的目的就是誰調用這個類,調用類的類加載器就負責加載這個類。只有當它的加載類為null時,即沒有任何加載器可用時,才使用getClassLoader0()這個native方法,這是啟動類加載器的實現方法,如果不是java lib目錄里的庫,該類是不會被加載的。
通過學習java 的包掃描和類加載,我簡單的了解了java類加載器的用法。
能力有限,如有錯誤請告知一聲。
ps:學而不思則罔,思而不學則殆。