2019独角兽企业重金招聘Python工程师标准>>>
最近遇到关于SpringMVC包扫描的问题,借此机会想自己实现一个类似的包扫描机制,实际上原理很简单,不过所需要的文件类是File和JarFile。
public class ClassScanner {
public static void main(String[] args) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try {
URL resource = contextClassLoader.getResource("com/google/gson");
URI uri = resource.toURI();
if("file".equals(uri.getScheme()))
{
File f = new File(uri.getPath());
System.out.println(f);
System.out.println(f.list());
System.out.println(Arrays.asList(f.list()));
}
else if("jar".equals(uri.getScheme()))
{
String path = resource.getFile();
String[] pathParts = path.split("!");
String jarFilePath = pathParts[0].substring(pathParts[0].indexOf("/"));
System.out.println(jarFilePath);
JarFile jarFile = new JarFile(jarFilePath);
System.out.println(jarFile.entries());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
不过网上已经有了,这里转载一下。
package com.itkt.mtravel.hotel.util;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class PackageUtil {
public static void main(String[] args) throws Exception {
String packageName = "com.wang.vo.request.hotel";
// List classNames = getClassName(packageName);
List classNames = getClassName(packageName, false);
if (classNames != null) {
for (String className : classNames) {
System.out.println(className);
}
}
}
/**
* 获取某包下(包括该包的所有子包)所有类
* @param packageName 包名
* @return 类的完整名称
*/
public static List getClassName(String packageName) {
return getClassName(packageName, true);
}
/**
* 获取某包下所有类
* @param packageName 包名
* @param childPackage 是否遍历子包
* @return 类的完整名称
*/
public static List getClassName(String packageName, boolean childPackage) {
List fileNames = null;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String packagePath = packageName.replace(".", "/");
URL url = loader.getResource(packagePath);
if (url != null) {
String type = url.getProtocol();
if (type.equals("file")) {
fileNames = getClassNameByFile(url.getPath(), null, childPackage);
} else if (type.equals("jar")) {
fileNames = getClassNameByJar(url.getPath(), childPackage);
}
} else {
fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage);
}
return fileNames;
}
/**
* 从项目文件获取某包下所有类
* @param filePath 文件路径
* @param className 类名集合
* @param childPackage 是否遍历子包
* @return 类的完整名称
*/
private static List getClassNameByFile(String filePath, List className, boolean childPackage) {
List myClassName = new ArrayList();
File file = new File(filePath);
File[] childFiles = file.listFiles();
for (File childFile : childFiles) {
if (childFile.isDirectory()) {
if (childPackage) {
myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage));
}
} else {
String childFilePath = childFile.getPath();
if (childFilePath.endsWith(".class")) {
childFilePath = childFilePath.substring(childFilePath.indexOf("\\classes") + 9, childFilePath.lastIndexOf("."));
childFilePath = childFilePath.replace("\\", ".");
myClassName.add(childFilePath);
}
}
}
return myClassName;
}
/**
* 从jar获取某包下所有类
* @param jarPath jar文件路径
* @param childPackage 是否遍历子包
* @return 类的完整名称
*/
private static List getClassNameByJar(String jarPath, boolean childPackage) {
List myClassName = new ArrayList();
String[] jarInfo = jarPath.split("!");
String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/"));
String packagePath = jarInfo[1].substring(1);
try {
JarFile jarFile = new JarFile(jarFilePath);
Enumeration entrys = jarFile.entries();
while (entrys.hasMoreElements()) {
JarEntry jarEntry = entrys.nextElement();
String entryName = jarEntry.getName();
if (entryName.endsWith(".class")) {
if (childPackage) {
if (entryName.startsWith(packagePath)) {
entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
myClassName.add(entryName);
}
} else {
int index = entryName.lastIndexOf("/");
String myPackagePath;
if (index != -1) {
myPackagePath = entryName.substring(0, index);
} else {
myPackagePath = entryName;
}
if (myPackagePath.equals(packagePath)) {
entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
myClassName.add(entryName);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return myClassName;
}
/**
* 从所有jar中搜索该包,并获取该包下所有类
* @param urls URL集合
* @param packagePath 包路径
* @param childPackage 是否遍历子包
* @return 类的完整名称
*/
private static List getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) {
List myClassName = new ArrayList();
if (urls != null) {
for (int i = 0; i < urls.length; i++) {
URL url = urls[i];
String urlPath = url.getPath();
// 不必搜索classes文件夹
if (urlPath.endsWith("classes/")) {
continue;
}
String jarPath = urlPath + "!/" + packagePath;
myClassName.addAll(getClassNameByJar(jarPath, childPackage));
}
}
return myClassName;
}
}
由于我们并不确定jar包生成时采用的哪种方式,如果采用默认生成jar包的方式,那我们通过Thread.currentThread().getContextClassLoader().getResource()是获取不到的,因此我增加了从所有jar包中搜索提供的包域名,这样功能就完善了很多。