在现在好多应用场景中,我们需要得到某个包名下面所有的类, 包括我们自己在src里写的java类和一些第三方提供的jar包里的类,那么怎么来实现呢?
今天带大家来完成这件事。
先分享代码:
1.这个类是一个抽象类,对类的处理交给用户,所以就有了dealClass的抽象方法。
1 package com.mec.packscanner.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 import java.util.jar.JarFile; 12 13 public abstract class PackageScanner { 14 public PackageScanner() {} 15 16 public abstract void dealClass(Class<?> klass); 17 18 //扫描一般的包。 19 private void scanPackage(String packageName,File currentfile) { 20 File[] filelist = currentfile.listFiles(new FileFilter() { 21 //FileFilter是文件过滤器,源代码只写了一个accapt的抽象方法。 22 @Override 23 public boolean accept(File pathName) { 24 if(pathName.isDirectory()) { //判断是否是目录 25 return true; 26 } 27 return pathName.getName().endsWith(".class"); 28 } 29 }); 30 31 for(File file:filelist) { 32 if(file.isDirectory()) { 33 scanPackage(packageName + "." + file.getName(),file); 34 }else { 35 String fileName = file.getName().replace(".class", ""); 36 String className = packageName + "." + fileName; 37 try { 38 Class<?> klass = Class.forName(className);//取出所有的类 39 if(klass.isAnnotation() //不扫描注解类、枚举类、接口和八大基本类型。 40 ||klass.isEnum() 41 ||klass.isInterface() 42 ||klass.isPrimitive()) { 43 continue; 44 } 45 dealClass(klass); 46 } catch (ClassNotFoundException e) { 47 e.printStackTrace(); 48 } 49 } 50 } 51 } 52 53 //扫描jar包方法。 54 private void scanPackage(URL url) throws IOException { 55 JarURLConnection urlConnection = (JarURLConnection) url.openConnection(); 56 JarFile jarfile = urlConnection.getJarFile(); 57 Enumeration<JarEntry> jarEntries = jarfile.entries(); 58 while(jarEntries.hasMoreElements()) { 59 JarEntry jarEntry = jarEntries.nextElement(); 60 String jarName = jarEntry.getName(); 61 if(!jarName.endsWith(".class")) { 62 continue; 63 } 64 String className = jarName.replace(".class", "").replaceAll("/", "."); 65 66 try { 67 Class<?> klass = Class.forName(className); 68 if (klass.isAnnotation() 69 || klass.isInterface() 70 || klass.isEnum() 71 || klass.isPrimitive()) { 72 continue; 73 } 74 dealClass(klass); 75 } catch (ClassNotFoundException e) { 76 e.printStackTrace(); 77 } 78 } 79 } 80 81 //用类名扫描 82 public void packageScan(Class<?> klass) { 83 packageScan(klass.getPackage().getName()); 84 } 85 86 //用包名进行扫描 87 public void packageScan(String packageName) { 88 String packOpperPath = packageName.replace(".","/"); 89 90 //线程上下文类加载器得到当前的classpath的绝对路径.(动态加载资源) 91 ClassLoader classloader = Thread.currentThread().getContextClassLoader(); 92 try { 93 //(Thread.currentThread().getContextClassLoader().getResource("")) 94 //(来得到当前的classpath的绝对路径的URI表示法。) 95 Enumeration<URL> resources = classloader.getResources(packOpperPath); 96 while(resources.hasMoreElements()) { 97 //先获得本类的所在位置 98 URL url = resources.nextElement(); 99 100 //url.getProtocol()是获取URL的HTTP协议。 101 if(url.getProtocol().equals("jar")) { 102 //判断是不是jar包 103 scanPackage(url); 104 }else { 105 //此方法不会自动将链接中的非法字符转义。 106 //而在File转化成URI的时候,会将链接中的特殊字符如#或!等字符进行编码。 107 File file = new File(url.toURI()); 108 if(!file.exists()) { 109 continue; 110 } 111 scanPackage(packageName,file); 112 } 113 } 114 } catch (IOException e) { 115 e.printStackTrace(); 116 } catch (URISyntaxException e) { 117 e.printStackTrace(); 118 } 119 } 120 }
这个是抽象类,对于扫描,我们只提供扫描的工具,而定义抽象方法是往外接,通过使用者的使用来决定用类名还是包名。
对于jar包的扫描,可以进JarURLConnection类和JarFile类的源码中可以理解。
2.定义测试类,它是扫描jar包的:
1 package com.mec.packscanner.test; 2 3 import com.mec.packscanner.core.PackageScanner; 4 5 public class Test { 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.getName()); 13 14 } 15 }.packageScan("com.mec.xml_view.core");; 16 } 17 18 }
结果:
从结果我们可以看出把jar包中的每一个class都输出了,匿名内部类都被扫描出来了。
我们来看看普通包的结果吧:
1 package com.mec.packscanner.test; 2 3 import com.mec.packscanner.core.PackageScanner; 4 5 public class Test { 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.getName()); 13 14 } 15 }.packageScan("com.mec.server_client.core");; 16 } 17 18 }
对普通的包也是,这个例子除了接口,其他的都被扫描出来了。
若有漏洞,请指正!感谢您的阅读。