我要写一个包扫描工具,该工具实现从指定目录往下遍历,最终找到以.class文件结尾的类,将该类的元类对象以抽象方法参数的形式传给用户。

步骤: 1.  根据指定目录找出绝对路径,根据Protocol(协议)将目录分为jar目录和普通目录;

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

    2.  分别处理jar目录和普通目录。

    3.  处理至找到了以.class文件结尾的类,将这个类的元类对象以抽象方法参数的形式传给用户。

直接贴代码:

package com.mec.util; import java.io.File; import java.net.JarURLConnection; import java.net.URL; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; public abstract class PackageScanner { public PackageScanner() { } public void scannerPackage(String packageName) { String packagePath = packageName.replace('.', '/'); //Eclipse下父目录与子目录以.相隔 //真正的路径中是以‘/’或‘\’相隔,此路径以‘\’相隔
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { Enumeration<URL> resources = classLoader.getResources(packagePath); //得到绝对路径
              while (resources.hasMoreElements()) {    URL url = resources.nextElement();    if (url.getProtocol().equals("jar")) { //通过Protocol(协议)可以区分开jar文件和普通文件
 scannerJar(url); // 将处理jar文件的代码单独写成一个内部方法,避免代码量过大
                } else { File root = new File(url.toURI()); //将url转化成uri,以此创建File对象,后面解析就变成了对File的处理
 scannerDirectory(root, packageName); // 同理将处理普通文件的代码单独也写成一个内部方法
 } } } catch ( Exception e) { e.printStackTrace(); } } private void scannerDirectory(File currentFile, String packageName) { if (!currentFile.isDirectory()) { return; } File[] files = currentFile.listFiles(); // 得到File对象类型的【完整路径】的数组
        for (File file : files) { if (file.isFile() && file.getName().endsWith(".class")) { String fileName = file.getName().replace(".class", ""); //去除掉后缀 .class
                String className = packageName + "." + fileName; // 得到带包名的类,为取得元类对象做准备
                try { Class<?> klass = Class.forName(className); dealClass(klass); //将得到的元类对象通过抽象方法参数传递给用户,以便用户后续操作。
                } catch (ClassNotFoundException e) { e.printStackTrace(); } } else if (file.isDirectory()) { scannerDirectory(file, packageName + "." + file.getName()); // 此处采用递归,只要是目录就继续往下一层遍历,直到file.isFile()为true,且以.class结尾
 } } } private void scannerJar(URL url) { try { JarURLConnection urlConnection = (JarURLConnection) url.openConnection(); JarFile jarFile = urlConnection.getJarFile(); // 取得jar文件的引用
            Enumeration<JarEntry> jarEntries = jarFile.entries(); //JarFile 的 entries 方法返回一个所有条目的 Enumeration 对象
            while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); //开始遍历,每个个体都是一个 JarEntry, 存在getName()方法
                String name = jarEntry.getName(); if (jarEntry.isDirectory() || !name.endsWith(".class")) { continue; } name = name.replace(".class", "");   //去除掉后缀 .class
                String className = name.replace('/', '.'); Class<?> klass = Class.forName(className); dealClass(klass); //将得到的元类对象通过抽象方法参数传递给用户,以便用户后续操作。
 } } catch (Exception e) { e.printStackTrace(); } } public abstract void dealClass(Class<?> klass); }

 

 经测试,上述代码可以完成包扫描过程。如果有些地方看不懂,可以上网查一查 。初学者学到这时,不应被  " 巫师的咒语  "吓倒,因为工具复杂,而不愿接受。相反,应站在工具本身发挥的作用角度来思考。积累的多了,见识的广了,才有资格去参悟那些  “  巫师的咒语  ”。

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄