java 加载class文件路径_动手实现MVC: 1. Java 扫描并加载包路径下class文件
背景
用过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文件相关推荐
- java 根据类名示例化类_如何使用示例从Java中的类路径加载资源
java 根据类名示例化类 Java中的类路径不仅用于加载.class文件,而且还可以用于加载资源,例如属性文件,图像,图标,缩略图或任何二进制内容. Java提供了API来将这些资源读取为Input ...
- python 文件路径_「按需学Python」 1. Glob库遍历路径/文件
小前言: 本人Python小白,因为最近想整理下近10几年的老照片,然后就有了写脚本批处理的想法.初始需求其实很简单,就是筛选自己想要的照片到指定文件夹,然后按照exif信息重命名照片为拍摄时间_拍摄 ...
- 我的世界电脑版java路径_我的世界启动器Java路径怎么设置?java路径设置攻略
我的世界这款游戏在电脑上打开是需要用到启动器的,不过很多玩家会经常碰到java路径设置不正确等等情况,那么我的世界启动器Java路径怎么设置呢?下面巴士小编就给大家带来java路径设置攻略. 我的世界 ...
- 我的世界设置java路径_我的世界启动器Java路径怎么设置?java路径设置攻略
我的世界这款游戏在电脑上打开是需要用到启动器的,不过很多玩家会经常碰到java路径设置不正确等等情况,那么我的世界启动器Java路径怎么设置呢?下面巴士小编就给大家带来java路径设置攻略. 我的世界 ...
- java里class有什么用_安装JDK时的java和javac命令有什么用?
相信大家都装过JDK吧,在装JDK时我们会在命令提示符窗口中通过java和javac两个命令来检测我们的环境变量是否配置正确,那么你知道java和javac两个命令有什么用吗? 在了解这两个命令的作用 ...
- labview当前vi路径_对于LabVIEW程序为什么生成EXE后,涉及到路径的输出不正确了?...
问题提出 使用LabVIEW编写应用程序时,相信很多小伙伴遇到过这样的问题,在VI程序中涉及到路径的问题时,比如在程序开始运行时,需要自动读取当前目录下某个文件的内容作为参数的初始配置,或者自动加载当 ...
- java显示一张图片不显示_微信图片不可显示java解决方法
场景: 微信上传了图片素材,返回了图片url,然后不能在img标签中正常显示. 原因是微信做了图片防盗连接. 解决方法: 原理:使用你的服务端脚本,远程抓取图片,然后输出image/* 格式,就可以了 ...
- java中build是什么意思_科普 eclipse中的Java build
在刚学eclipse的时候,build path是经常会用到的,但经常就是跟着教程走,额就不太懂这是干嘛的,然后今天看见极客视频里有相关的讲解,来记录一下. Build Path 是指定Java工程所 ...
- java中i+=2什么意思_三分钟看懂Java中i++与++i的性能差别以及循环中如何使用
在Java中,自增是一种非常常见的操作,在自增中,有两种写法,一种是前缀自增(++i),一种是后缀自增(i++).这里主要简单介绍两种自增的差别. 一.含义差别 前缀自增和后缀自增是不同的.前缀自增( ...
最新文章
- HDU 5552 Bus Routes(2015合肥现场赛A,计数,分治NTT)
- 第15章 MiniVGGNet:更深的CNNs
- jquery 源码分析初步
- bt服务器搭建 linux_Linux 搭建 我的世界(MC) 基岩版服务器
- eclipse配置mysql教程_在Eclipse连接mysql-----配置jbdc_MySQL
- Redis报错:redis.exceptions.ResponseError: MISCONF Redis is configured to save RDB snap
- 韶关无线电厂台式计算机,中国芯片30年的历史 它背后有哪些不为人知的故事?...
- 碎片时间学习前端,我推荐这些~
- java foreach跳出本次循环_Java中提供三种常用的循环语句
- P1742 最小圆覆盖
- 使用自动机的Lucene新的邻近查询
- 深入继承之抽象类和接口综合分析及完整案列解说(一)
- 酒吧声场测试软件,做到以下几点 酒吧音响效果出奇的好
- 侧栏广告 image flash
- 竟还有这样的代码注释我笑喷了
- 线上服务器出现CPU飙升问题该怎么办?
- 斥资57亿美金,Facebook 入局印度 | 凌云时刻
- mysql id 主键 外键_mysql主键 外键
- 年薪50万的程序员_如何才能撩到年薪50万的程序员?
- matlab运行.m文件的命令,Matlab:从命令行运行m文件
热门文章
- Springboot 项目中 xml文件读取yml 配置文件
- Crystal Reports第一张报表
- 成功试验基于C#/.NET的Android开发
- 学会这二十个正则表达式,能让你少些1000行代码!
- 【Git入门之五】版本管理
- request_do?send方法
- leetcode981. 基于时间的键值存储(treemap)
- 回溯算法和贪心算法_回溯算法介绍
- 我如何使用React和Typescript在freeCodeCamp中构建天气应用
- 给matrix重新列名_如何认真升级Mac终端(甚至给它一个Matrix主题)