包扫描在框架中应用很广泛,在spring中,通过给自己的类加注解的方式,利用spring的包扫描,完成依赖注入。
1 package com.test.package_scanner.core; 2 3 import java.io.File; 4 import java.io.FileFilter; 5 import java.io.IOException; 6 import java.net.JarURLConnection; 7 import java.net.URISyntaxException; 8 import java.net.URL; 9 import java.util.Enumeration; 10 import java.util.jar.JarEntry; 11 12 public abstract class PackageScanner { 13 14 public PackageScanner() { 15 } 16 17 // scanPackage方法的重载 18 public void scanPackage(Class<?> klass) { 19 scanPackage(klass.getPackage().getName()); 20 } 21 22 public void scanPackage(String packageName) { 23 // 将包名称转换为路径名称的形式 24 String packagePath = packageName.replace(".", "/"); 25 26 try { 27 // 由类加载器得到URL的枚举 28 Enumeration<URL> resources = Thread.currentThread() 29 .getContextClassLoader() 30 .getResources(packagePath); 31 32 while (resources.hasMoreElements()) { 33 URL url = resources.nextElement(); 34 35 // 处理jar包 36 if (url.getProtocol().equals("jar")) { 37 parse(url); 38 } else { 39 File file = new File(url.toURI()); 40 41 if (file.exists()) { 42 // 处理普通包 43 parse(file, packageName); 44 } 45 } 46 } 47 } catch (IOException e) { 48 e.printStackTrace(); 49 } catch (URISyntaxException e) { 50 e.printStackTrace(); 51 } 52 } 53 // 抽象方法,由用户自行处理扫描到的类 54 public abstract void dealClass(Class<?> klass); 55 56 // jar包的扫描 57 private void parse(URL url) throws IOException { 58 Enumeration<JarEntry> jarEntries = ((JarURLConnection) url.openConnection()) 59 .getJarFile().entries(); 60 61 while (jarEntries.hasMoreElements()) { 62 JarEntry jarEntry = jarEntries.nextElement(); 63 String jarName = jarEntry.getName(); 64 65 if (!jarEntry.isDirectory() && jarName.endsWith(".class")) { 66 // 将文件路径名转换为包名称的形式 67 dealClassName(jarName.replace("/", ".").replace(".class", "")); 68 } 69 } 70 } 71 72 // 普通包的扫描 73 private void parse(File curFile, String packageName) { 74 File[] fileList = curFile.listFiles(new FileFilter() { 75 // 筛选文件夹和class文件,其余文件不处理 76 @Override 77 public boolean accept(File pathname) { 78 return pathname.isDirectory() || pathname.getName().endsWith(".class"); 79 } 80 }); 81 82 // 目录就是一颗树,对树进行递归,找到class文件 83 for (File file : fileList) { 84 String fileName = file.getName(); 85 if (file.isDirectory()) { 86 parse(file, packageName + "." + fileName); 87 } else { 88 String className = packageName + "." + fileName.replace(".class", ""); 89 dealClassName(className); 90 } 91 } 92 } 93 94 // 将找到的class文件生成类对象 95 private void dealClassName(String className) { 96 try { 97 Class<?> klass = Class.forName(className); 98 99 // 注解、接口、枚举、原始类型不做处理 100 if (!klass.isAnnotation() 101 && !klass.isInterface() 102 && !klass.isEnum() 103 && !klass.isPrimitive()) { 104 dealClass(klass); 105 } 106 } catch (ClassNotFoundException e) { 107 e.printStackTrace(); 108 } 109 } 110 111 }
对如下目录扫描
1 package com.test.package_scanner.demo; 2 3 import com.test.package_scanner.core.PackageScanner; 4 5 public class Demo { 6 7 public static void main(String[] args) { 8 new PackageScanner() { 9 10 @Override 11 public void dealClass(Class<?> klass) { 12 System.out.println(klass); 13 } 14 }.scanPackage("com"); 15 } 16 17 }
结果如下