背景

用过spring框架之后,有个指定扫描包路径,然后自动实例化一些bean,这个过程还是比较有意思的,抽象一下,即下面三个点

如何扫描包路径下所有的class文件

如何扫描jar包中对应包路径下所有的class文件

如何加载class文件

实现

目标

我们的目标是给定一个包路径,然后加载这个包路径下的所有class

考虑两种场景

包路径为依赖第三方jar包中的

包路径为自己的业务代码中的 --》 常见的一种是业务代码会编译成class文件,即扫描文件

实现

针对上面两种场景,分开说明

1. 扫描文件

实现流程比较清晰:

根据包名,获取绝对地址,直接进入包对应的目录

扫描目录下所有文件

加载所有的class文件;

如果是目录,迭代遍历目录下的class文件

加载class文件

获取包对应的绝对地址,这里先不说,下面直接给出进入目录,加载所有class文件的代码

/**

* 扫描包路径下的所有class文件

*

* @param pkgName 包名

* @param pkgPath 包对应的绝对地址

* @param classes 保存包路径下class的集合

*/

private static void findClassesByFile(String pkgName, String pkgPath, Set> classes) {

File dir = new File(pkgPath);

if (!dir.exists() || !dir.isDirectory()) {

return;

}

// 过滤获取目录,or class文件

File[] dirfiles = dir.listFiles(pathname -> pathname.isDirectory() || pathname.getName().endsWith("class"));

if (dirfiles == null || dirfiles.length == 0) {

return;

}

String className;

Class clz;

for (File f : dirfiles) {

if (f.isDirectory()) {

findClassesByFile(pkgName + "." + f.getName(),

pkgPath + "/" + f.getName(),

classes);

continue;

}

// 获取类名,干掉 ".class" 后缀

className = f.getName();

className = className.substring(0, className.length() - 6);

// 加载类

clz = loadClass(pkgName + "." + className);

if (clz != null) {

classes.add(clz);

}

}

}

2. 扫描jar

流程和上面一样,实现上稍稍有些区别,由之前的扫描文件变成遍历JarFile

/**

* 扫描包路径下的所有class文件

*

* @param pkgName 包名

* @param jar jar文件

* @param classes 保存包路径下class的集合

*/

private static void findClassesByJar(String pkgName, JarFile jar, Set> classes) {

String pkgDir = pkgName.replace(".", "/");

Enumeration entry = jar.entries();

JarEntry jarEntry;

String name, className;

Class> claze;

while (entry.hasMoreElements()) {

jarEntry = entry.nextElement();

name = jarEntry.getName();

if (name.charAt(0) == '/') {

name = name.substring(1);

}

if (jarEntry.isDirectory() || !name.startsWith(pkgDir) || !name.endsWith(".class")) {

// 非指定包路径, 非class文件

continue;

}

// 去掉后面的".class", 将路径转为package格式

className = name.substring(0, name.length() - 6);

claze = loadClass(className.replace("/", "."));

if (claze != null) {

classes.add(claze);

}

}

}

3. 扫描包

上面是具体的扫class文件的过程,那么如何根据包获取对应的jarFile or 包对应的绝对地址呢?

主要利用的是 XXX.class.getClassLoader().getResources(package), 具体如下

/**

* 扫描包路径下所有的class文件

*

* @param pkg

* @return

*/

public static Set> getClzFromPkg(String pkg) {

Set> classes = new LinkedHashSet<>();

String pkgDirName = pkg.replace('.', '/');

try {

Enumeration urls = PkgUtil.class.getClassLoader().getResources(pkgDirName);

while (urls.hasMoreElements()) {

URL url = urls.nextElement();

String protocol = url.getProtocol();

if ("file".equals(protocol)) {// 如果是以文件的形式保存在服务器上

String filePath = URLDecoder.decode(url.getFile(), "UTF-8");// 获取包的物理路径

findClassesByFile(pkg, filePath, classes);

} else if ("jar".equals(protocol)) {// 如果是jar包文件

JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();

findClassesByJar(pkg, jar, classes);

}

}

} catch (IOException e) {

e.printStackTrace();

}

return classes;

}

4. 类加载

这个还是比较简单的,一搜一大把,直接贴出

private static Class> loadClass(String fullClzName) {

try {

return Thread.currentThread().getContextClassLoader().loadClass(fullClzName);

} catch (ClassNotFoundException e) {

log.error("load class error! clz: {}, e:{}", fullClzName, e);

}

return null;

}

测试

要愉快的测试这一功能,你可以选择一个jar包,如 org.slf4j, 然后自己创建几个测试类,包名也是已 org.slf4j开头,然后调用上面的方法

Class> set = PkgUtil.getClzFromPkg("org.slf4j");

因为这个工具类我是放在 quick-mvc 工程的,所以就直接使用了我定义的包 com.hust.hui,因为没啥通用性,就给出本机测试的演示图好了

其他

公众号获取更多:

java 加载class文件路径_动手实现MVC: 1. Java 扫描并加载包路径下class文件相关推荐

  1. java 根据类名示例化类_如何使用示例从Java中的类路径加载资源

    java 根据类名示例化类 Java中的类路径不仅用于加载.class文件,而且还可以用于加载资源,例如属性文件,图像,图标,缩略图或任何二进制内容. Java提供了API来将这些资源读取为Input ...

  2. python 文件路径_「按需学Python」 1. Glob库遍历路径/文件

    小前言: 本人Python小白,因为最近想整理下近10几年的老照片,然后就有了写脚本批处理的想法.初始需求其实很简单,就是筛选自己想要的照片到指定文件夹,然后按照exif信息重命名照片为拍摄时间_拍摄 ...

  3. 我的世界电脑版java路径_我的世界启动器Java路径怎么设置?java路径设置攻略

    我的世界这款游戏在电脑上打开是需要用到启动器的,不过很多玩家会经常碰到java路径设置不正确等等情况,那么我的世界启动器Java路径怎么设置呢?下面巴士小编就给大家带来java路径设置攻略. 我的世界 ...

  4. 我的世界设置java路径_我的世界启动器Java路径怎么设置?java路径设置攻略

    我的世界这款游戏在电脑上打开是需要用到启动器的,不过很多玩家会经常碰到java路径设置不正确等等情况,那么我的世界启动器Java路径怎么设置呢?下面巴士小编就给大家带来java路径设置攻略. 我的世界 ...

  5. java里class有什么用_安装JDK时的java和javac命令有什么用?

    相信大家都装过JDK吧,在装JDK时我们会在命令提示符窗口中通过java和javac两个命令来检测我们的环境变量是否配置正确,那么你知道java和javac两个命令有什么用吗? 在了解这两个命令的作用 ...

  6. labview当前vi路径_对于LabVIEW程序为什么生成EXE后,涉及到路径的输出不正确了?...

    问题提出 使用LabVIEW编写应用程序时,相信很多小伙伴遇到过这样的问题,在VI程序中涉及到路径的问题时,比如在程序开始运行时,需要自动读取当前目录下某个文件的内容作为参数的初始配置,或者自动加载当 ...

  7. java显示一张图片不显示_微信图片不可显示java解决方法

    场景: 微信上传了图片素材,返回了图片url,然后不能在img标签中正常显示. 原因是微信做了图片防盗连接. 解决方法: 原理:使用你的服务端脚本,远程抓取图片,然后输出image/* 格式,就可以了 ...

  8. java中build是什么意思_科普 eclipse中的Java build

    在刚学eclipse的时候,build path是经常会用到的,但经常就是跟着教程走,额就不太懂这是干嘛的,然后今天看见极客视频里有相关的讲解,来记录一下. Build Path 是指定Java工程所 ...

  9. java中i+=2什么意思_三分钟看懂Java中i++与++i的性能差别以及循环中如何使用

    在Java中,自增是一种非常常见的操作,在自增中,有两种写法,一种是前缀自增(++i),一种是后缀自增(i++).这里主要简单介绍两种自增的差别. 一.含义差别 前缀自增和后缀自增是不同的.前缀自增( ...

最新文章

  1. HDU 5552 Bus Routes(2015合肥现场赛A,计数,分治NTT)
  2. 第15章 MiniVGGNet:更深的CNNs
  3. jquery 源码分析初步
  4. bt服务器搭建 linux_Linux 搭建 我的世界(MC) 基岩版服务器
  5. eclipse配置mysql教程_在Eclipse连接mysql-----配置jbdc_MySQL
  6. Redis报错:redis.exceptions.ResponseError: MISCONF Redis is configured to save RDB snap
  7. 韶关无线电厂台式计算机,中国芯片30年的历史 它背后有哪些不为人知的故事?...
  8. 碎片时间学习前端,我推荐这些~
  9. java foreach跳出本次循环_Java中提供三种常用的循环语句
  10. P1742 最小圆覆盖
  11. 使用自动机的Lucene新的邻近查询
  12. 深入继承之抽象类和接口综合分析及完整案列解说(一)
  13. 酒吧声场测试软件,做到以下几点 酒吧音响效果出奇的好
  14. 侧栏广告 image flash
  15. 竟还有这样的代码注释我笑喷了
  16. 线上服务器出现CPU飙升问题该怎么办?
  17. 斥资57亿美金,Facebook 入局印度 | 凌云时刻
  18. mysql id 主键 外键_mysql主键 外键
  19. 年薪50万的程序员_如何才能撩到年薪50万的程序员?
  20. matlab运行.m文件的命令,Matlab:从命令行运行m文件

热门文章

  1. Springboot 项目中 xml文件读取yml 配置文件
  2. Crystal Reports第一张报表
  3. 成功试验基于C#/.NET的Android开发
  4. 学会这二十个正则表达式,能让你少些1000行代码!
  5. 【Git入门之五】版本管理
  6. request_do?send方法
  7. leetcode981. 基于时间的键值存储(treemap)
  8. 回溯算法和贪心算法_回溯算法介绍
  9. 我如何使用React和Typescript在freeCodeCamp中构建天气应用
  10. 给matrix重新列名_如何认真升级Mac终端(甚至给它一个Matrix主题)