前言
本篇博客专门就mybatis-enhance
的ClassTools类进行分析, 请先移步读mybatis-enhance开源项目。
分析
getClasses方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| public static Set<Class<?>> getClasses(String pack){ Set<Class<?>> classes = new LinkedHashSet<Class<?>>(); boolean recursive = true; String packageName = pack; String packageDirName = packageName.replace('.', '/'); Enumeration<URL> dirs; try{ dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); while (dirs.hasMoreElements()){ URL url = dirs.nextElement(); String protocol = url.getProtocol(); if ("file".equals(protocol)) { System.err.println("file类型的扫描"); String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
}else if ("jar".equals(protocol)) { System.err.println("jar类型的扫描"); JarFile jar; try{ jar = ((JarURLConnection) url.openConnection()).getJarFile(); Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()){ JarEntry entry = entries.nextElement(); String name = entry.getName(); if (name.charAt(0) == '/') { name = name.substring(1); } if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); if (idx != -1) { packageName = name.substring(0, idx).replace('/', '.'); } if ((idx != -1) || recursive) { if (name.endsWith(".class") && !entry.isDirectory()) { String className = name.substring(packageName.length() + 1, name.length() - 6); try{ classes.add(Class.forName(packageName + '.' + className)); }catch (ClassNotFoundException e){ e.printStackTrace(); } } } } } }catch (IOException e){ e.printStackTrace(); } } } }catch (IOException e){ e.printStackTrace(); }
return classes; }
|
注释已经将逻辑解释的很清楚, 首先使用ClassLoader
的getResources()
根据包名获取到URL
的一个枚举集合, 然后根据URL协议来判断当前元素是一个文件还是一个jar包。
如果是一个文件, 那么根据url
地址来获取到文件的绝对路径, 然后根据路径获取到类名, 添加到Set集合中。
如果是一个jar包, 那么Java有一个专门的JarURLConnection
来搞定这个事情。
值得注意的是当协议为File
时, 有一个单独的方法来添加集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public static void findAndAddClassesInPackageByFile( String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes){ File dir = new File(packagePath); if (!dir.exists() || !dir.isDirectory()) { return; } File[] dirfiles = dir.listFiles(new FileFilter(){
public boolean accept(File file){ return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")); } }); for (File file : dirfiles){ if (file.isDirectory()) { findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes); }else{ String className = file.getName().substring(0, file.getName().length() - 6); try{ classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); }catch (ClassNotFoundException e){ e.printStackTrace(); } } } }
|
具体的思路是: 先获取到目录下的所有的file, 接下来有一个递归, 可以将子目录下的文件检测到, 并使用ClassLoader
的loadClass()
获取到class实例, 添加进集合中。
嗯, ClassTools
就分析到这里。