抠腚爱揉曼 Coding Iron Man

2Jul/104

获取指定package路径下的所有class

最近有个需求,通过Annotation来获取class。刚好spring的Annotation注册方式是这样的,于是把spring相关的代码翻了一遍,翻完之后就尝试自己简单实现了下,结果如下。

package us.vifix.a.ape.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import sun.net.www.protocol.jar.JarURLConnection;
import us.vifix.a.ape.scheduler.annotation.ExecutorAnnonationFilter;

/**
 * author: Anson
 * http://a.vifix.us
 */
public final class ClassUtils {
	public static List getClassFromPackageWithFilter(String packageName, ClassFilter filter) {
		List results = new ArrayList();
		// 将包名转换为路径名
		String packageDirName = packageName.replace('.', '/');
		// 通过路径获取URL
		Enumeration resources = null;
		try {
			resources = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
		} catch (IOException e) {
			return results;
		}
		// 遍历获取的URL
		while (resources.hasMoreElements()) {
			URL url = resources.nextElement();
			// 如果是jar包
			if ("jar".equals(url.getProtocol())) {
				JarFile jarFile = null;
				try {
					JarURLConnection conn = (JarURLConnection) url.openConnection();
					jarFile = conn.getJarFile();
				} catch (IOException e) {
					continue;
				}
				// 遍历jar包中的所有entry
				for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) {
					JarEntry entry = entries.nextElement();
					String entryName = entry.getName();
					// 是以指定路径开始&&是class文件&&不是内部类
					if (entryName.startsWith(packageDirName)
							&& entryName.endsWith(".class")
							&& entryName.indexOf("$") == -1) {
						// 把路径转变为类名 us/vifix/a/Class.class - us.vifix.a.Class
						String className = entryName.replace('/', '.').substring(0, entryName.length() - 6);
						// 过滤器
						if (filter != null && !filter.filter(className)) continue;
						try {
							results.add(Class.forName(className));
						} catch (ClassNotFoundException e) {
							continue;
						}
					}
				}
			// 如果是文件系统
			} else if ("file".equals(url.getProtocol())) {
				String filePath = null;
				try {
					filePath = URLDecoder.decode(url.getFile(), "UTF-8");
				} catch (UnsupportedEncodingException e) {
					continue;
				}
				// 获取根目录并迭代获取所有class
				File rootDirectory = new File(filePath);
				getClassFromDirectory(packageName, rootDirectory, filter, results);
			}
		}

		return results;
	}

	private static void getClassFromDirectory(String packageName, File directory, ClassFilter filter, List results) {
		// 如果不存在或者不是目录就直接返回
		if (!directory.exists() || !directory.isDirectory()) return;
		// 获取目录下文件列表 过滤规则为是目录或者是class文件并且不是内部类
		File[] files = directory.listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				return (pathname.isDirectory() || (pathname.getName().endsWith(".class") && pathname.getName().indexOf("$") == -1));
			}
		});
		// 遍历
		for (File file : files) {
			// 如果是目录 迭代
			if (file.isDirectory()) {
				getClassFromDirectory(packageName + "." + file.getName(), file, filter, results);
			} else {
				// 去掉末尾的.class 组装成className
				String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
				// 过滤器
				if (filter != null && !filter.filter(className)) continue;
				try {
					results.add(Class.forName(className));
				} catch (ClassNotFoundException e) {
					continue;
				}
			}
		}
	}

	public static void main(String[] args) {
		List result = getClassFromPackageWithFilter("javax.crypto", null);
		System.out.println("=== result1 ===");
		for (Class clazz : result) {
			System.out.println(clazz);
		}
		result = getClassFromPackageWithFilter("us.vifix.a.ape", new ExecutorAnnonationFilter());
		System.out.println("=== result2 ===");
		for (Class clazz : result) {
			System.out.println(clazz);
		}
	}
}

Posted by Anson

Comments (4) Trackbacks (0)
  1. 我靠 不会自动换行啊 羊子控快去调教

  2. 或者找个自适应宽度的皮 哥的1080p显示器就优势了

  3. 我想不通了,Chronium 6.0.419.0 (48453)在reader里面看代码是正常的,博客里面就不是。囧。


Leave a comment

(required)

No trackbacks yet.