1. 程式人生 > >Java如何掃描指定package下所有的類

Java如何掃描指定package下所有的類

在寫一個MVC框架,需要從包中掃描出元件並註冊到容器中,而JDK沒有提供現成的從方法,只能自己實現。

功能:
給定一個包名,程式設計得到該包(和其所有子包)下所有的類檔案。如,輸入包名com.myapp.util, 輸出該包下類的全限定名com.myapp.util.StringUtils, com.app.util.ImageUtils等。

思路:
有的web server在部署執行時會解壓jar包,因此class檔案會在普通的檔案目錄下。如果web server不解壓jar包,則class檔案會直接存在於Jar包中。對於前者,只需定位到class檔案所在目錄,然後將class檔名讀取出即可;對於後者,則需先定位到jar包所在目錄,然後使用JarInputStream

讀取Jar包,得到class類名。

實現:
這是從寫好的專案程式碼中直接copy出來的,如果要執行這段程式碼,需要把所有的Logger.debug改成System.out.println()

/**
 * This scanner is used to find out all classes in a package.
 * Created by whf on 15-2-26.
 */
public class ClasspathPackageScanner implements PackageScanner {
    private Logger logger = LoggerFactory.getLogger(ClasspathPackageScanner.class);

    private
String basePackage; private ClassLoader cl; /** * Construct an instance and specify the base package it should scan. * @param basePackage The base package to scan. */ public ClasspathPackageScanner(String basePackage) { this.basePackage = basePackage; this.cl = getClass().getClassLoader(); } /** * Construct an instance with base package and class loader. * @param
basePackage The base package to scan. * @param cl Use this class load to locate the package. */
public ClasspathPackageScanner(String basePackage, ClassLoader cl) { this.basePackage = basePackage; this.cl = cl; } /** * Get all fully qualified names located in the specified package * and its sub-package. * * @return A list of fully qualified names. * @throws IOException */ @Override public List<String> getFullyQualifiedClassNameList() throws IOException { logger.info("開始掃描包{}下的所有類", basePackage); return doScan(basePackage, new ArrayList<>()); } /** * Actually perform the scanning procedure. * * @param basePackage * @param nameList A list to contain the result. * @return A list of fully qualified names. * * @throws IOException */ private List<String> doScan(String basePackage, List<String> nameList) throws IOException { // replace dots with splashes String splashPath = StringUtil.dotToSplash(basePackage); // get file path URL url = cl.getResource(splashPath); String filePath = StringUtil.getRootPath(url); // Get classes in that package. // If the web server unzips the jar file, then the classes will exist in the form of // normal file in the directory. // If the web server does not unzip the jar file, then classes will exist in jar file. List<String> names = null; // contains the name of the class file. e.g., Apple.class will be stored as "Apple" if (isJarFile(filePath)) { // jar file if (logger.isDebugEnabled()) { logger.debug("{} 是一個JAR包", filePath); } names = readFromJarFile(filePath, splashPath); } else { // directory if (logger.isDebugEnabled()) { logger.debug("{} 是一個目錄", filePath); } names = readFromDirectory(filePath); } for (String name : names) { if (isClassFile(name)) { //nameList.add(basePackage + "." + StringUtil.trimExtension(name)); nameList.add(toFullyQualifiedName(name, basePackage)); } else { // this is a directory // check this directory for more classes // do recursive invocation doScan(basePackage + "." + name, nameList); } } if (logger.isDebugEnabled()) { for (String n : nameList) { logger.debug("找到{}", n); } } return nameList; } /** * Convert short class name to fully qualified name. * e.g., String -> java.lang.String */ private String toFullyQualifiedName(String shortName, String basePackage) { StringBuilder sb = new StringBuilder(basePackage); sb.append('.'); sb.append(StringUtil.trimExtension(shortName)); return sb.toString(); } private 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<>(); while (null != entry) { String name = entry.getName(); if (name.startsWith(splashedPackageName) && isClassFile(name)) { nameList.add(name); } entry = jarIn.getNextJarEntry(); } return nameList; } private List<String> readFromDirectory(String path) { File file = new File(path); String[] names = file.list(); if (null == names) { return null; } return Arrays.asList(names); } private boolean isClassFile(String name) { return name.endsWith(".class"); } private boolean isJarFile(String name) { return name.endsWith(".jar"); } /** * For test purpose. */ public static void main(String[] args) throws Exception { PackageScanner scan = new ClasspathPackageScanner("cn.fh.lightning.bean"); scan.getFullyQualifiedClassNameList(); } }

上面的程式碼中用到了StringUtils類,如下:

public class StringUtil {
    private StringUtil() {

    }

    /**
     * "file:/home/whf/cn/fh" -> "/home/whf/cn/fh"
     * "jar:file:/home/whf/foo.jar!cn/fh" -> "/home/whf/foo.jar"
     */
    public 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
     */
    public static String dotToSplash(String name) {
        return name.replaceAll("\\.", "/");
    }

    /**
     * "Apple.class" -> "Apple"
     */
    public 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
     */
    public static String trimURI(String uri) {
        String trimmed = uri.substring(1);
        int splashIndex = trimmed.indexOf('/');

        return trimmed.substring(splashIndex);
    }
}

執行結果:
這裡寫圖片描述

相關推薦

Java如何掃描指定package所有的

在寫一個MVC框架,需要從包中掃描出元件並註冊到容器中,而JDK沒有提供現成的從方法,只能自己實現。 功能: 給定一個包名,程式設計得到該包(和其所有子包)下所有的類檔案。如,輸入包名com.myapp.util, 輸出該包下類的全限定名com.myapp.

java讀取指定package所有class

public als sta 功能 accept smo bstr 文件的 get JAVA如何掃描一個包下面的所有類,並加載到內存中去? spring中有一個<context:component-scan base-package="com.controller"

java 遍歷指定所有,返回完整名。工具,可以直接拷入使用

1、說明:       此類為本人開發的工具類,具體應用在什麼地方呢。本人在實際專案中,許可權管理這一塊有所應用,應該是許可權這一塊有所需求而開發的。 應用場景說明:許可權資源自動化生產時,使用者點選介面的一鍵生成資源時,介面中就會遍歷指定controller包下所有

掃描指定目錄所有圖片文件

沒有 extern wpa gets 當前 indexof path resolv cti String myparent=newPath.substring(0, newPath.lastIndexOf("/")).substring(newPath.substrin

Java 掃描指定的檔案

第一種方法:利用google的guava掃描指定的包 StringBuffer value = new StringBuffer(); String packageName = "com.business.service.impl"; ClassPath classpat

java 獲取指定目錄所有檔案的名稱

需要將檔名稱及路徑存到資料庫中 String path ="/db/java/Data3/"; StringBuffer str = new StringBuffer(""); File

掃描指定目錄所有圖片檔案

<span style="font-size:18px;"> String myparent=newPath.substring(0, newPath.lastIndexOf("/")).substring(newPath.substrin

Java 掃描所有(包括jar包)

package com.MyUtils.file;import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.JarURLConnection; i

Java 列出資料夾所有檔案,符合條件的檔案複製到指定目錄

import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; public class TestFile { public static void main(String[] a

史上最完整掃描所有(含Jar包掃描,maven子專案掃描

要掃描包下的所有類,分類路徑下掃描和jar包掃描兩種,其中jar包掃描又分專案中引入的三方jar包,同級maven的多個子專案jar相互引用,還有jdk jar包(這裡不考慮,一般沒哪個專案會掃描jdk jar包裡的類). 我先宣告一個介面,用於應對不同型別的class

java程式 一次改變指定目錄所有檔案編碼(包括子目錄中的檔案)

package transCoding; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInpu

Java 替換資料夾所有檔案中指定的內容

我的上一篇部落格提到了找到檔案中的中文。之前的程式碼還可以做一個擴充套件。可以作為一個強大的查詢功能使用。關鍵字查詢,這個功能大家可以思考一下,今後我的部落格也會去貼上這樣的關鍵字查詢的功能的程式碼,能跟大家討論分析一下。 今天的替換的功能也是基於上篇

JAVA獲取同一路徑所有或介面實現

整個測試程式碼如下: Java程式碼   package find;   import java.io.File;   import java.io.IOException;   import java.net.URL;   import java.util.A

獲取包所有中的註解的值 (java工具

作用:這個工具類主要的作用就是獲取類中的註解的值。 應用場景:做許可權的時候獲取@RequestMapping();的值,自動新增到資料庫中。 /** * getRequestMappingValue方法描述: * 作者:thh

java找到資料夾所有指定格式檔案並輸出到txt

import java.io.*; public class CopyDirsMain { /** * 注意,pw初始化不能在遞迴裡面。在遞迴時可能會出錯 * * */ public static void main(String[] args) {

Java呼叫在default package

今天工作的時候,遇到一個坑,寫一個功能需要呼叫dll的檔案,然後硬體方提供的API的程式程式碼是需要把他們的讀取資料的程式碼放在default package,但是我需要在其他包名在呼叫,普通的呼叫和匯入都不行,就只能通過反射來呼叫。 通過反射即可呼叫defa

抓取指定路徑所有文檔名

mds 所有 -- 2.6 div ast txt rom char --方法1: EXEC xp_dirtree ‘\\172.6.6.6\D$\TEXT\‘,1,1 --方法2: CREATE TABLE #TXT_Name (NAME VARCHAR( 2000)

掃描指定路徑的全部請求路徑(基於SpringMVC)

ada access cto url ssm private 博客 ble ack 通過上面兩篇博客,我們能夠得到指定類上的全部請求路徑。現在需要的是,給定一個指定的路徑,獲取全部的請求路徑。 public class RequestUrlScannerHelper {

Java遍歷包中所有方法註解

|| asm 服務器 ret nec next 代碼 自定義 tco 一.代碼實例 import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.l

Java基礎知識-java.util.concurrent包常見的使用

finall iss con value 通信 out 否則 app ted 一,Condition 一個場景,兩個線程數數,同時啟動兩個線程,線程A數1、2、3,然後線程B數4、5、6,最後線程A數7、8、9,程序結束,這涉及到線程之間的通信。 public class