前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >java-解决jar包反射获取不到类

java-解决jar包反射获取不到类

作者头像
潇洒
发布于 2023-10-20 02:44:19
发布于 2023-10-20 02:44:19
73300
代码可运行
举报
文章被收录于专栏:石头岛石头岛
运行总次数:0
代码可运行

前言

在开发一个基础工具包给业务组的小伙伴们使用的时候,发现一个小问题,就是在反射的时候在自己电脑上运行的正常,但是打成jar包后,就class not fuond,有点奇怪。 如果能借助Spring这个都不是事,关键是不能用。

场景复现

下面的目的是,找到这个指定包下的所有类,对我指定了注解的类进行加载,其实就是一个可以灵活装配、拆卸的策略模式。这样业务的类可以通过指定注解来选择是否成为业务的一部分。 下面这段代码在IDE中运行正常。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类加载工厂
 *
 * @author liukai
 * @since 2015/9/9.
 */
public class GeneratorFactory {

  public static Map<String, TransactionCreator> creators = new HashMap<>();

  static {
    // 基于 IDE 运行
    reflectByClass();
  }

  public static void reflectByClass() {
    try {
      ArrayList<Class> creatorsClass = new ArrayList<>();
      ArrayList<File> classFiles = new ArrayList<>();
      // 拿到关键接口
      Class<?> interfaceClass = Class.forName("com.liukai.test.generate.TransactionCreator");
      String packageName = interfaceClass.getPackage().getName();
      // 拿到 ClassLoader
      ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
      String path = packageName.replace(".", "/");
      System.out.println("path: " + path);
      Enumeration<URL> resources = contextClassLoader.getResources(path);
      System.out.println("Enumeration<URL> resources: " + resources);
      while (resources.hasMoreElements()) {
        URL url = resources.nextElement();
        System.out.println("url.getFile(): " + url.getFile());
        classFiles.add(new File(url.getFile()));
      }
      for (File file : classFiles) {
        creatorsClass.addAll(findClass(file, packageName));
      }

      for (Class clazz : creatorsClass) {
        System.out.println("Class clazz : creatorsClass");
        Creator declaredAnnotation = (Creator) clazz.getAnnotation(Creator.class);
        if (declaredAnnotation != null) {
          System.out.println("creators: add" + declaredAnnotation.type());
          creators.put(declaredAnnotation.type(), (TransactionCreator) clazz.newInstance());
        }
      }
    } catch (ClassNotFoundException | IOException | IllegalAccessException | InstantiationException e) {
      e.printStackTrace();
    }
  }

  public static TransactionCreator getGenerator(String type) {
    System.out.println("creators: " + creators.size());
    return creators.get(type);
  }

  private static ArrayList<Class> findClass(File file, String packagename) {
    ArrayList<Class> list = new ArrayList<>();
    if (!file.exists()) {
      return list;
    }
    File[] files = file.listFiles();
    for (File file2 : files) {
      if (file2.isDirectory()) {
        assert !file2.getName().contains(".");
        ArrayList<Class> arrayList = findClass(file2, packagename + "." + file2.getName());
        list.addAll(arrayList);
      } else if (file2.getName().endsWith(".class")) {
        try {
          list.add(Class.forName(packagename + '.' + file2.getName().substring(0,
                  file2.getName().length() - 6)));
        } catch (ClassNotFoundException e) {
          e.printStackTrace();
        }
      }
    }
    return list;
  }

}

解决方式: 由于打成jar包后,类路径多了一层jar,所以加载时,要考虑到jar包路径,以下这个demo,实际可以通过获取运行路径变量替换写死的路径。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类加载工厂
 *
 * @author liukai
 * @since 2015/9/9.
 */
public class GeneratorFactory {

  public static Map<String, TransactionCreator> creators = new HashMap<>();

  static {
    // 基于 jar 包反射
    reflectByJar();
  }

  public static void reflectByJar() {
    String path = "/Users/liukai/workspaces/java/test/build/libs/";
    String fileName = "test.jar";
    try {
      JarFile jarFile = new JarFile(path + fileName);
      Enumeration<JarEntry> e = jarFile.entries();
      JarEntry entry;
      while (e.hasMoreElements()) {
        entry = (JarEntry) e.nextElement();
        if (entry.getName().indexOf("META-INF") < 0 && entry.getName().indexOf(".class") >= 0) {
          String classFullName = entry.getName();
          //去掉后缀.class
          String className = classFullName.substring(0, classFullName.length() - 6).replace("/", ".");
          Class<?> clazz;
          try {
            try {
              if (!className.contains("com.liukai.test")) {
                continue;
              }
              System.out.println("Class clazz : creatorsClass:" + className);
              clazz = Class.forName(className);
              Creator declaredAnnotation = (Creator) clazz.getAnnotation(Creator.class);
              if (declaredAnnotation != null) {
                System.out.println("creators: add" + declaredAnnotation.type());
                creators.put(declaredAnnotation.type(), (TransactionCreator) clazz.newInstance());
              }
            } catch (ClassNotFoundException e1) {
              e1.printStackTrace();
            }

          } catch (Exception e1) {

          }

        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

总结

感觉还是不智能,应该有一个通用的方法,无论我是什么场景,只需要一套代码就解决,而不是用户来抽像,这个JDK应该得提供。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验