package hjp.smart4j.framework.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileFilter; import java.net.JarURLConnection; import java.net.URL; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; /** * 类操作工具类 */ public final class ClassUtil { private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class); /** * 获取类加载器 */ public static ClassLoader getClassLoader() { return Thread.currentThread().getContextClassLoader(); } /** * 加载类 * className为类的全包名 */ public static Class<?> loadClass(String className, boolean isInitialized) { Class<?> cls; try { cls = Class.forName(className, isInitialized, getClassLoader()); } catch (ClassNotFoundException e) { LOGGER.error("load class failure", e); throw new RuntimeException(); } return cls; } /** * 获取指定包名下的所有类 */ public static Set<Class<?>> getClassSet(String packageName) { Set<Class<?>> classSet = new HashSet<Class<?>>(); try { Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/")); while (urls.hasMoreElements()) { URL url = urls.nextElement(); if (url != null) { String protocol = url.getProtocol();//url协议 if (protocol.equals("file")) { String packagePath = url.getPath().replaceAll("%20", " "); addClass(classSet, packagePath, packageName); } else if (protocol.equals("jar")) { JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection(); if (jarURLConnection != null) { JarFile jarFile = jarURLConnection.getJarFile(); if (jarFile != null) { Enumeration<JarEntry> jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); String jarEntryName = jarEntry.getName(); if (jarEntryName.endsWith(".class")) { String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", "."); doAddClass(classSet, className); } } } } } } } } catch (Exception e) { LOGGER.error("get class set failure", e); throw new RuntimeException(e); } return classSet; } private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) { final File[] files = new File(packagePath).listFiles(new FileFilter() { public boolean accept(File file) { //过滤出Class文件或文件夹 return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory(); } }); for (File file : files) { String fileName = file.getName(); if (file.isFile()) { //如果是类文件构造类文件全包名 String className = fileName.substring(0, fileName.lastIndexOf(".")); if (StringUtil.isNotEmpty(packageName)) { className = packageName + "." + className; } doAddClass(classSet, className);//这个方法就是用Class.forName方法得到类,加到classSet集合中 } else { //如果是文件夹 //构造此文件夹相对路径 String subPacakgePath = fileName; if (StringUtil.isNotEmpty(subPacakgePath)) { subPacakgePath = packagePath + "/" + subPacakgePath; } //构造此文件夹包名路径 String subPacakgeName = fileName; if (StringUtil.isNotEmpty(subPacakgeName)) { subPacakgeName = packageName + "." + subPacakgeName; } //递归加载类 addClass(classSet, subPacakgePath, subPacakgeName); } } } private static void doAddClass(Set<Class<?>> classSet, String className) { Class<?> cls = loadClass(className, false); classSet.add(cls); } }
1、通过类加载器,得到指定路径下所有资源,返回Enumeration<URL>集合
2、类文件要么是以.class结尾的文件,要么是在jar包中以.class结尾的文件
3、URL 统一资源定位器,遍历Enumeration<URL>集合,分别处理url协议为file或jar的文件
4、如果是file协议,分两种,一种是文件,另一种是文件夹;得到file协议的每一个class格式文件,分析出该class文件全包名,Class.forName方法得到该类
5、如果是jar协议,得到jar包内文件,遍历得到class格式文件,分析出该class文件全包名,Class.forName方法得到该类