Java获取类下的所有子类

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

01em……


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


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


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


13.png


要下个版本才能修复。那么就只能网上找找方法,然后自己加工下实现了,具体代码如下,亲测可用,其中包含很多的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@Slf4jpublic 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 unchecked                collect.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);    }}


好了,冒泡结束,感谢没有取消关注的小伙伴!!!爱你们~

相关文章
|
4天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
10 0
|
4天前
|
Java
Java 15 神秘登场:隐藏类解析未知领域
Java 15 神秘登场:隐藏类解析未知领域
10 0
|
6天前
|
安全 Java
append在Java中是哪个类下的方法
append在Java中是哪个类下的方法
21 9
|
6天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
25 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
|
7天前
|
存储 安全 Java
java多线程之原子操作类
java多线程之原子操作类
|
8天前
|
Java
Java中的多线程实现:使用Thread类与Runnable接口
【4月更文挑战第8天】本文将详细介绍Java中实现多线程的两种方法:使用Thread类和实现Runnable接口。我们将通过实例代码展示如何创建和管理线程,以及如何处理线程同步问题。最后,我们将比较这两种方法的优缺点,以帮助读者在实际开发中选择合适的多线程实现方式。
19 4
|
9天前
|
Java
在Java中,多态性允许不同类的对象对同一消息做出响应
【4月更文挑战第7天】在Java中,多态性允许不同类的对象对同一消息做出响应
15 2
|
14天前
|
Java
Java通过反射获取类调用方法
Java通过反射获取类调用方法
18 0
|
18天前
|
存储 安全 Java
【Java技术专题】「攻破技术盲区」攻破Java技术盲点之unsafe类的使用指南(打破Java的安全管控— sun.misc.unsafe)
【Java技术专题】「攻破技术盲区」攻破Java技术盲点之unsafe类的使用指南(打破Java的安全管控— sun.misc.unsafe)
32 0
|
25天前
|
Java
java面向对象高级分层实例_测试类(main方法所在的类)
java面向对象高级分层实例_测试类(main方法所在的类)
8 1