您当前的位置: 首页 >  spring

java持续实践

暂无认证

  • 2浏览

    0关注

    746博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Spring 源码之实现Class对象的提取

java持续实践 发布时间:2021-03-06 19:21:54 ,浏览量:2

文章目录
      • 获取Class类的集合
      • 单元测试

获取Class类的集合

获取某个包下的类集合 代码如下 . 主要是三步

  1. 获取类加载器: 通过Thread.currentThread().getContextClassLoader() 来获取
  2. 通过类加载器获取到加载的资源信息 , 是通过classLoader.getResource获取, 传入包路径, 注意要把. , 转化为"/".
  3. 获取类的集合: 主要是 过滤出文件类型, 目前只处理file类型的协议, 再获取包下的实际绝对路径, 最后是通过绝对路径, 去递归获取类的集合 .

完整代码如下

/**
     * 获取某个包下的类集合 :
     * 1. 获取到类加载器:
     * 目的:   获取项目发布的实际路径 . 不同的系统表示路径的方法不同. 如果是war或jar包就找不到jar包.
     * 类加载器: ClassLoader
     * 

* 2. 通过类加载器获取到加载的资源信息 * 3. 根据不同的资源类型, 采取不同的方式获取资源的集合 * * @param packageName 包名 * @return 类集合 */ public static Set extractPackageClass(String packageName) { // 1. 获取到类加载器 ClassLoader classLoader = getClassLoader(); // 2. 通过类加载器获取到加载的资源信息 URL url = classLoader.getResource(packageName.replace(".", "/")); if (url == null) { log.error(" 无法获取到资源, 从此包中 : " + packageName); return null; } // 3. 根据不同的资源类型(目前只解析file类型的), 采取不同的方式获取资源的集合 Set classSet = null; // 过滤出文件类型资源 if (url.getProtocol().equalsIgnoreCase(FILE_PROTOCOL)) { classSet = new HashSet(); // 获取package的实际路径 File packageDirectory = new File(url.getPath()); // 递归获取目标package 里面的所有class文件(包括子package里的class文件) extractClassFile(classSet, packageDirectory, packageName); } // 返回所有的类实例 return classSet; } /** * 递归获取目标package里面的所有class文件(包括子package里的class文件) * * @param emptyClassSet 装载目标类的集合 * @param fileSource 目录或文件 * @param packageName 包名 */ private static void extractClassFile(Set emptyClassSet, File fileSource, String packageName) { if (!fileSource.isDirectory()) { // 如果资源不是文件夹, 那么直接结束 return; } // 获取一个文件夹下的所有文件或者文件夹, 不包含子文件夹 File[] files = fileSource.listFiles(new FileFilter() { @Override public boolean accept(File file) { if (file.isDirectory()) { // 筛选出只含有文件夹的资源 return true; } else { //获取文件的绝对值路径 String absolutePath = file.getAbsolutePath(); if (absolutePath.endsWith(".class")) { // 如果是class文件, 加载到内存中 addToClassSet(absolutePath); } } return false; } // 根据class文件的绝对值路径, 获取并生成class对象, 并放入classSet中 private void addToClassSet(String absolutePath) { // 1. 从class文件的绝对值路径里提取出包含了package的类名 // 如absolutePath D:\mycode\spring_study\simpleframework\src\main\java\org\simpleframework\core\annotation\Component.class // 如 org.simpleframework.core.annotation.Component // 把\ 换成 . absolutePath = absolutePath.replace(File.separator, "."); // 例如传入的包名为org.simpleframework.core 代表从 org.simpleframework.core 开始截取 String className = absolutePath.substring(absolutePath.indexOf(packageName)); // 去掉 末尾的class className = className.substring(0, className.lastIndexOf(".")); // 2. 通过反射机制, 获取对应的class对象并加入到classSet里 Class targetClass = loadClass(className); // 把加载的类放入集合中 emptyClassSet.add(targetClass); } }); // 迭代遍历之前, 先判断是否为空 if (files != null) { for (File f : files) { // 递归调用 extractClassFile(emptyClassSet, f, packageName); } } } /** * 获取class 对象 * * @param className class全名 = package+类名 * @return */ public static Class loadClass(String className) { try { return Class.forName(className); } catch (ClassNotFoundException e) { // 加载类异常 log.error("load class error", e); throw new RuntimeException(e); } } /** * 获取当前的ClassLoader * 程序是通过线程执行的, 获取当前执行的方法的线程, 便能通过线程属的类加载器获取程序资源信息 * * @return */ public static ClassLoader getClassLoader() { return Thread.currentThread().getContextClassLoader(); }

单元测试

pom中加入如下的依赖

       
            org.junit.jupiter
            junit-jupiter-api
            5.5.2
            test
        

在test包中, 编写如下的测试类

public class ClassUtilTest {

    // 表明测试用例的含义
    @DisplayName("extractPackageClassTest 提取目标类方法")
    @Test
    public void extractPackageClassTest(){
        Set classes = ClassUtil.extractPackageClass("demo.annotation");
           if (classes != null) {
            for (Class aClass : classes) {
                System.out.println(aClass);
            }
        }
        Assertions.assertEquals(5, classes.size());
    }
}

在我当前的项目中, demo.annotation包下有五个类, 因此在上面的断言中, 我断言了5个. 在这里插入图片描述 控制台打印如下 , 测试通过 , 并且成功打印获取了如下的五个类.

关注
打赏
1658054974
查看更多评论
立即登录/注册

微信扫码登录

0.0375s