Java如何扫描指定package下所有的类
来源:互联网 发布:永诚网络 编辑:程序博客网 时间:2024/05/16 12:08
在写一个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); }}
执行结果:
0 0
- Java如何扫描指定package下所有的类
- java读取指定package下的所有class
- java读取指定package下的所有class
- java读取指定package下的所有class
- java读取指定package下的所有class
- java读取指定package下的所有class
- java读取指定package下的所有class
- Java扫描classpath指定包路径下所有class
- Java 扫描指定包下的文件
- 扫描指定目录下所有图片文件
- 如何利用Java遍历所有的指定文件目录下的所有文件
- 删除指定目录下的所有文件的java类
- 删除指定目录下的所有文件的java类
- 删除指定目录下的所有文件的java类
- 删除指定目录下的所有文件的java类
- MFC递归扫描指定文件夹下的所有文件包括子文件夹下的文件。
- java获取指定目录下所有指定扩展名的文件
- Linux目录扫描:打印指定目录下的所有文件及目录
- DWR使用笔记
- objective-c 内管管理3
- BZOJ 2764 [JLOI2011]基因补全
- Android camera bring up
- esp8266路由模式设置
- Java如何扫描指定package下所有的类
- 动态申请和释放一个二维数组
- 三十四、异常(一)异常抛出、异常捕获、异常传播
- LeetCoder 解题报告 3Sum
- 查找试题--互换函数swap初试
- 快速傅里叶变换算法
- 重新加载 vimrc
- redis集群简易实验
- 任意进制转换算法