Java反射如何获取jar包下的某个类的所有子类?

2023-11-11 00:59

本文主要是介绍Java反射如何获取jar包下的某个类的所有子类?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首本来觉得实现这个功能应该挺简单的,而且市面上也已经有了开源的工具比如:Reflections,简单的两句代码就能实现这个功能:

Reflections reflections = new Reflections("my.project");
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);

这个在本地Idea调试时确实也都比较好用。不过,当遇到需要加载依赖jar里的对象时,在部署启动Tomcat服务的时候就会遇到无法到子类的问题。这个目前GitHub的issue上也有提到:

图片

要下个版本才能修复。那么就只能网上找找方法,然后自己加工下实现了,具体代码如下,亲测可用,其中包含很多的Java类加载的知识,确实值得细品,主要关注点:

  1. 当加载jar包对象时,代码中url的protocol在Idea调试时是file,而部署到服务器上后,就成了jar,猜测这也是Reflections工具无效的原因(具体源码没去看,知识猜测);

  2. 类加载在本地和Tomcat上有挺大的区别,这个可以看引申链接知识。

package com.pupu.kael.core.utils;import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;import java.io.File;
import java.lang.reflect.Modifier;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;@NoArgsConstructor
@Slf4j
public class ClassUtils {/*** 获取类包下的所有子类** @param type* @param <T>* @return*/public static <T> Set<Class<? extends T>> getSubTypesOf(Class<T> type) {Set<Class<?>> classes = getClasses(type.getPackage().getName());Set<Class<? extends T>> collect = new HashSet<>();for (Class<?> aClass : classes) {if (!type.equals(aClass) && type.isAssignableFrom(aClass) && !aClass.isInterface() && !Modifier.isAbstract(aClass.getModifiers())) {//noinspection uncheckedcollect.add((Class<? extends T>) aClass);}}return collect;}/*** 获取某个包下的所有类*/public static Set<Class<?>> getClasses(String packageName) {Set<Class<?>> classSet = new HashSet<>();try {String sourcePath = packageName.replace(".", "/");Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(sourcePath);while (urls.hasMoreElements()) {URL url = urls.nextElement();if (url != null) {String protocol = url.getProtocol();if ("file".equals(protocol)) {String packagePath = url.getPath().replaceAll("%20", " ");addClass(classSet, packagePath, packageName);} else if ("jar".equals(protocol)) {JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();if (jarURLConnection != null) {JarFile jarFile = jarURLConnection.getJarFile();if (jarFile != null) {Enumeration<JarEntry> jarEntries = jarFile.entries();while (jarEntries.hasMoreElements()) {JarEntry jarEntry = jarEntries.nextElement();String jarEntryName = jarEntry.getName();if (jarEntryName.contains(sourcePath) && jarEntryName.endsWith(".class")) {String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");doAddClass(classSet, className);}}}}}}}} catch (Exception e) {log.error("获取子类失败", e);}return classSet;}private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {File[] files = new File(packagePath).listFiles(file -> (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory());for (File file : files) {String fileName = file.getName();if (file.isFile()) {String className = fileName.substring(0, fileName.lastIndexOf("."));if (StringUtils.isNotEmpty(packageName)) {className = packageName + "." + className;}doAddClass(classSet, className);} else {String subPackagePath = fileName;if (StringUtils.isNotEmpty(packagePath)) {subPackagePath = packagePath + "/" + subPackagePath;}String subPackageName = fileName;if (StringUtils.isNotEmpty(packageName)) {subPackageName = packageName + "." + subPackageName;}addClass(classSet, subPackagePath, subPackageName);}}}/*** 加载类*/public static Class<?> loadClass(String className, boolean isInitialized) {Class<?> cls;try {cls = Class.forName(className, isInitialized, Thread.currentThread().getContextClassLoader());} catch (ClassNotFoundException e) {throw new RuntimeException(e);}return cls;}/*** 加载类(默认将初始化类)*/public static Class<?> loadClass(String className) {return loadClass(className, true);}private static void doAddClass(Set<Class<?>> classSet, String className) {Class<?> cls = loadClass(className, false);classSet.add(cls);}
}

代码来源博客:

https://blog.csdn.net/u011943534/article/details/95518628

引申的类加载知识,绝对值得一看:

https://www.cnblogs.com/zfyouxi/p/4803072.html

关注公众号获取更多内容,有问题也可在公众号提问哦:

强哥叨逼叨

叨逼叨编程、互联网的见解和新鲜事

 

这篇关于Java反射如何获取jar包下的某个类的所有子类?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/386467

相关文章

springboot健康检查监控全过程

《springboot健康检查监控全过程》文章介绍了SpringBoot如何使用Actuator和Micrometer进行健康检查和监控,通过配置和自定义健康指示器,开发者可以实时监控应用组件的状态,... 目录1. 引言重要性2. 配置Spring Boot ActuatorSpring Boot Act

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python