背景

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

  1. 如何扫描包路径下所有的class文件
  2. 如何扫描jar包中对应包路径下所有的class文件
  3. 如何加载class文件

实现

目标

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

考虑两种场景

  1. 包路径为依赖第三方jar包中的
  2. 包路径为自己的业务代码中的 --》 常见的一种是业务代码会编译成class文件,即扫描文件

实现

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

1. 扫描文件

实现流程比较清晰:

  • 根据包名,获取绝对地址,直接进入包对应的目录
  • 扫描目录下所有文件
    • 加载所有的class文件;
    • 如果是目录,迭代遍历目录下的class文件
  • 加载class文件

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

/*** 扫描包路径下的所有class文件** @param pkgName 包名* @param pkgPath 包对应的绝对地址* @param classes 保存包路径下class的集合*/
private static void findClassesByFile(String pkgName, String pkgPath, Set<Class<?>> 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<Class<?>> classes) {String pkgDir = pkgName.replace(".", "/");Enumeration<JarEntry> 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<Class<?>> getClzFromPkg(String pkg) {Set<Class<?>> classes = new LinkedHashSet<>();String pkgDirName = pkg.replace('.', '/');try {Enumeration<URL> 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");

Java 扫描并加载包路径下class文件相关推荐

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

    背景 用过spring框架之后,有个指定扫描包路径,然后自动实例化一些bean,这个过程还是比较有意思的,抽象一下,即下面三个点 如何扫描包路径下所有的class文件 如何扫描jar包中对应包路径下所 ...

  2. 加载指定路径下所有文件

    工作中经常遇到加载某个文件夹下的所有文件,然后对文件遍历,今天写代码时遇到一个好的类ArrayDeque,整理一下,做一下笔记 下面写了一个测试类 package com.hpzx.test;impo ...

  3. el-image中src加载assets路径下图片使用require避免加载不到

    场景 el-image中图片的数据源加载assets路径下的照片. 正确加载方式. <el-imagestyle="width: 732px; height: 48px":s ...

  4. 【ClassLoader】实现自定义类加载器加载指定路径下的Class文件和Jar包

    文章目录 前言 自定义类加载器加载.class文件 自定义类加载器加载jar包文件 前言 在web开发中,一般我们是不需要去自己实现类加载器的,常见的web容器已经帮我们实现了指定路径下的加载,比如我 ...

  5. Thinkphp 5.1 PC和手机端加载不同路径下的模板~功能实现

    现在开发虽然很多都是前后端分离了,但是还是很多项目没有前后端分离 现在要实现功能 就是手机端和电脑端增加不同路径下面的模板~ DEMO 仅供参考 1.在公共函数增加函数  isMobile 验证设备是 ...

  6. java 运行 加载jar,java运行时加载额外的 jar 包或 class

    首先讲下java类加载的顺序 每个类加载器有自己的名字空间,对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅加载一次.不管该类有没有变化,下次再需要加载时,它只是从自己的缓存中直接返回已经 ...

  7. 【JVM】Java类的加载流程以及双亲委派,全盘托管,以及如何打破双亲委派机制

    JVM基础生命周期流程图 只有main()方法的java程序执行流程 classLoader.loadClass()的类加载流程(除引导类,所有类都一样) 加载:通过IO查找读取磁盘上的字节码文件,在 ...

  8. Java的ClassLoader加载是怎么保证安全的?

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 1.类加载机制 Java中的源码.java后缀文件会在运行前被编译成.class后缀文件,文件内的字节码的本质就是一个 ...

  9. Python语言学习:利用python获取当前/上级/上上级目录路径(获取路径下的最后叶目录的文件名、合并两个不同路径下图片文件名等目录/路径案例、正确加载图片路径)之详细攻略

    Python语言学习:利用python获取当前/上级/上上级目录路径(获取路径下的最后叶目录的文件名.合并两个不同路径下图片文件名等目录/路径案例.正确加载图片路径)之详细攻略 目录 利用python ...

最新文章

  1. 使用__FILE__和__LINE__定位错误
  2. centos桌面进入服务器,解决如何在centos7桌面中打开终端_网站服务器运行维护
  3. 6数组排序的方法_JavaScript数组排序方法
  4. Flask的jinja输出json内容
  5. JLupin Next Server乍一看
  6. 安徽大学计算机教学平台c语言作业,安徽大学计算机教学部练习题与答案1.pdf
  7. 前端学习(1742):前端调试值之快速调试和修改
  8. Nginx端口映射(外网访问)
  9. readline_Swift readLine(),Swift print()
  10. HTML如何把输入框变成必填值,required输入框为必填项
  11. 用SDK包开发K66FX18学习笔记(3)
  12. 9款用HTML5/CSS3制作的动物、人物动画
  13. 透彻理解超级电容的11个参数
  14. 使用FDDB人脸样本检测库,测试自己的人脸检测算法性能并生成ROC曲线。
  15. HEXOFontmin
  16. (最全面的)各类RAID详解
  17. 2021-04-28 Mac上插入公式的三种方法
  18. win凭据添加计算机名,使用Windows凭据管理自动登录局域网的方法
  19. 职称评审业绩材料报告造假难解决?
  20. How to turn off checksum offload?

热门文章

  1. Fiddler抓取https相关设置
  2. mongodb 启动方法
  3. 怎么开发一个npm包
  4. POJ 2251 Dungeon Master (BFS最短路)
  5. SDUT2389Ballot evaluation
  6. 微软腾讯联手开发IM软件MQ QQ和MSN将于2009年停用
  7. 轻量级的日期时间控件Pikaday
  8. Error response from daemon: manifest not found.
  9. 探讨Express Router Route
  10. 让就医流程更智能 道一循推医院官方APP