1. 程式人生 > >【Java】包、jar包的掃描

【Java】包、jar包的掃描

package com.test.package_scanner.core;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;

public abstract class PackageScanner {

	public PackageScanner() {
	}
	
	// scanPackage方法的過載
	public void scanPackage(Class<?> klass) {
		scanPackage(klass.getPackage().getName());
	}
	
	public void scanPackage(String packageName) {
		// 將包名稱轉換為路徑名稱的形式
		String packagePath = packageName.replace(".", "/");
		
		try {
			// 由類載入器得到URL的列舉
			Enumeration<URL> resources = Thread.currentThread()
				.getContextClassLoader()
				.getResources(packagePath);
			
			while (resources.hasMoreElements()) {
				URL url = resources.nextElement();
				
				// 處理jar包
				if (url.getProtocol().equals("jar")) {
					parse(url);
				} else {
					File file = new File(url.toURI());
					
					if (file.exists()) {
						// 處理普通包
						parse(file, packageName);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}
	// 抽象方法,由使用者自行處理掃描到的類 
	public abstract void dealClass(Class<?> klass);
	
	// jar包的掃描
	private void parse(URL url) throws IOException {
		Enumeration<JarEntry> jarEntries = ((JarURLConnection) url.openConnection())
			.getJarFile().entries();
		
		while (jarEntries.hasMoreElements()) {
			JarEntry jarEntry = jarEntries.nextElement();
			String jarName = jarEntry.getName();
			
			if (!jarEntry.isDirectory() && jarName.endsWith(".class")) {
				// 將檔案路徑名轉換為包名稱的形式
				dealClassName(jarName.replace("/", ".").replace(".class", ""));
			}
		}
	}
	
	// 普通包的掃描
	private void parse(File curFile, String packageName) {
		File[] fileList = curFile.listFiles(new FileFilter() {
			// 篩選檔案和class檔案,其餘檔案不處理
			@Override
			public boolean accept(File pathname) {
				return pathname.isDirectory() || pathname.getName().endsWith(".class");
			}
		});
		
		// 目錄就是一顆樹,對樹進行遞迴,找到class檔案
		for (File file : fileList) {
			String fileName = file.getName();
			if (file.isDirectory()) {
				parse(file, packageName + "." + fileName);
			} else {
				String className = packageName + "." + fileName.replace(".class", "");
				dealClassName(className);
			}
		}
	}
	
	// 將找到的class檔案生成類物件
	private void dealClassName(String className) {
		try {
			Class<?> klass = Class.forName(className);
			
			// 註解、介面、列舉、原始型別不做處理
			if (!klass.isAnnotation()
					&& !klass.isInterface()
					&& !klass.isEnum()
					&& !klass.isPrimitive()) {
				dealClass(klass);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
}

對如下目錄掃描 在這裡插入圖片描述

package com.test.package_scanner.demo;

import com.test.package_scanner.core.PackageScanner;

public class Demo {

	public static void main(String[] args) {
		new PackageScanner() {
			
			@Override
			public void dealClass(Class<?> klass) {
				System.out.println(klass);
			}
		}.scanPackage("com");
	}

}

結果如下 在這裡插入圖片描述 其中帶有$1的是匿名內部類