java掃描包下所有類的完整路徑


轉自我的個人博客:java掃描包下所有類的完整路徑

 

最近在完善微信公眾號返利機器人訂單輪訓、跟蹤。

業務邏輯是定時任務調用淘客API,按一定條件查詢某時間段內的返利訂單。定時任務框架用的quartz,原先定時任務寫死在代碼中,此次優化將定時任務做成可視化配置,更加靈活、通用。

今天暫不討論、總結quartz定時任務可視化配置,后面單獨寫文章總結一下。

用過quartz的應該知道,所有的定時任務都是直接或間接的繼承Job類,我們把所有的job類放在同一個包下,做成可視化需要解決的就是掃描此包,獲取包下所有的job類。

直接貼上掃描包下所有類代碼

 

package com.gaoxiaobo.download.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;

/**
 * @Auther: gaoxiaobo
 * @Date: 2020/8/8 21:17
 * @Description:
 */
public class ClasspathPackageScanner {

    private static Logger logger = LoggerFactory.getLogger(ClasspathPackageScanner.class);
    private static ClassLoader cl = ClasspathPackageScanner.class.getClassLoader();



    /**
     *獲取指定包下的所有字節碼文件的全類名
     */
    public static List<String> getFullyQualifiedClassNameList(String basePackage) throws Exception {

        return doScan(basePackage, new ArrayList<>());
    }

    private static List<String> scanJar(String basePackage)throws Exception{
        List<String> clazz = new ArrayList<>();
        Enumeration<URL> urlEnumeration = Thread.currentThread().getContextClassLoader().getResources(basePackage.replace(".", "/"));
        while (urlEnumeration.hasMoreElements()) {
            URL url = urlEnumeration.nextElement();//得到的結果大概是:jar:file:/C:/Users/ibm/.m2/repository/junit/junit/4.12/junit-4.12.jar!/org/junit
            String protocol = url.getProtocol();//大概是jar
            System.out.println(protocol);
            if ("jar".equalsIgnoreCase(protocol)) {
                //轉換為JarURLConnection
                JarURLConnection connection = (JarURLConnection) url.openConnection();
                if (connection != null) {
                    JarFile jarFile = connection.getJarFile();
                    if (jarFile != null) {
                        //得到該jar文件下面的類實體
                        Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
                        while (jarEntryEnumeration.hasMoreElements()) {
                            /*entry的結果大概是這樣:
                                    org/
                                    org/junit/
                                    org/junit/rules/
                                    org/junit/runners/*/
                            JarEntry entry = jarEntryEnumeration.nextElement();
                            String jarEntryName = entry.getName();
                            //這里我們需要過濾不是class文件和不在basePack包名下的類
                            if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/",".").startsWith(basePackage)) {
                                String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
                                clazz.add(className);
                            }
                        }
                    }
                }
            }
        }
        return clazz;
    }

    /**
     *doScan函數
     * @param basePackage
     * @param nameList
     * @return
     * @throws IOException
     */
    private static List<String> doScan(String basePackage, List<String> nameList) throws Exception {
        String classpath = ClasspathPackageScanner.class.getResource("/").getPath();
        if (classpath.startsWith("file")){
            return scanJar(basePackage);
        }
        String splashPath = dotToSplash(basePackage);
        URL url = cl.getResource(splashPath);   //file:/D:/WorkSpace/java/ScanTest/target/classes/com/scan
        String filePath = getRootPath(url);

        List<String> names = null; // contains the name of the class file. e.g., Apple.class will be stored as "Apple"
        if (isJarFile(filePath)) {// 先判斷是否是jar包,如果是jar包,通過JarInputStream產生的JarEntity去遞歸查詢所有類
            if (logger.isDebugEnabled()) {
                logger.debug("{} 是一個JAR包", filePath);
            }
            names = readFromJarFile(filePath, splashPath);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("{} 是一個目錄", filePath);
            }
            names = readFromDirectory(filePath);
        }
        for (String name : names) {
            if (isClassFile(name)) {
                nameList.add(toFullyQualifiedName(name, basePackage));
            } else {
                doScan(basePackage + "." + name, nameList);
            }
        }
        if (logger.isDebugEnabled()) {
            for (String n : nameList) {
                logger.debug("找到{}", n);
            }
        }
        return nameList;
    }

    private static String toFullyQualifiedName(String shortName, String basePackage) {
        StringBuilder sb = new StringBuilder(basePackage);
        sb.append('.');
        sb.append(trimExtension(shortName));
        //打印出結果
        System.out.println(sb.toString());
        return sb.toString();
    }

    private static List<String> readFromJarFile(String jarPath, String splashedPackageName) throws IOException {
        if (logger.isDebugEnabled()) {
            logger.debug("從JAR包中讀取類: {}", jarPath);
        }
        JarInputStream jarIn = new JarInputStream(new FileInputStream(jarPath));
        JarEntry entry = jarIn.getNextJarEntry();
        List<String> nameList = new ArrayList<String>();
        while (null != entry) {
            String name = entry.getName();
            if (name.startsWith(splashedPackageName) && isClassFile(name)) {
                nameList.add(name);
            }

            entry = jarIn.getNextJarEntry();
        }

        return nameList;
    }

    private static List<String> readFromDirectory(String path) {
        File file = new File(path);
        String[] names = file.list();

        if (null == names) {
            return null;
        }

        return Arrays.asList(names);
    }

    private static boolean isClassFile(String name) {
        return name.endsWith(".class");
    }

    private static boolean isJarFile(String name) {
        return name.endsWith(".jar");
    }


    private static String getRootPath(URL url) {
        String fileUrl = url.getFile();
        int pos = fileUrl.indexOf('!');

        if (-1 == pos) {
            return fileUrl;
        }

        return fileUrl.substring(5, pos);
    }

    /**
     * "cn.fh.lightning" -> "cn/fh/lightning"
     * @param name
     * @return
     */
    private static String dotToSplash(String name) {
        return name.replaceAll("\\.", "/");
    }

    /**
     * "Apple.class" -> "Apple"
     */
    private static String trimExtension(String name) {
        int pos = name.indexOf('.');
        if (-1 != pos) {
            return name.substring(0, pos);
        }

        return name;
    }

    /**
     * /application/home -> /home
     * @param uri
     * @return
     */
    private static String trimURI(String uri) {
        String trimmed = uri.substring(1);
        int splashIndex = trimmed.indexOf('/');

        return trimmed.substring(splashIndex);
    }
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM