最近在学习java的反射和注解,实际情景中需要扫描某个包下的所有java类,然后使用类加载器加载类。
基本思路,获得程序的路径扫描src下某个包内的子包和java类,实现也比较简单。
运行环境:windows10+jdk1.8+eclipse
直接贴代码
packageorg.test.scanner;importjava.io.File;importjava.util.ArrayList;importjava.util.List;/** date:2019-07-23
**/
public classPackageScanner {private List>classes;private String packagePath = null;/** 无参构造方法,内部调用带参的构造方法。
*
* @throw classNotFound
**/
public PackageScanner() throwsClassNotFoundException {this("");
}/** 实现,调用fileScanner进行目录扫描和加载
*
* @param String 传入需要扫描的包
*
* @throw classNotFound*/
public PackageScanner(String basePackage) throwsClassNotFoundException {
packagePath= System.getProperty("user.dir") + "\\src\\";
String filePath= packagePath + basePackage.replace('.', '\\');
classes= new ArrayList>();
fileScanner(newFile(filePath));
}private void fileScanner(File file) throwsClassNotFoundException {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>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:学而不思则罔,思而不学则殆。