【问题标题】:loading jar at runtime and using its class在运行时加载 jar 并使用它的类
【发布时间】:2014-11-18 19:00:36
【问题描述】:

我有一个问题需要帮助。

问题陈述: 我正在使用一个 jar 生成 excel 表格格式的报告。仅当用户想要生成 excel 格式的报告时才需要此 jar。其他可用的报告格式有htmltxt,它们不需要这个jar。

当前用户生成html格式的报告,所以他说,当我不需要excel格式的报告时,为什么要下载这个jar并将其导出为classpath

现在的问题是如果这个 jar 被删除,这个构建将失败/因为所有对正在使用的类的导入都会出错。 Class.forName 可以在运行时加载类并且不会给我错误但是这样我将无法使用该类的方法,因为我无法获得该类的引用。

有没有办法或者这是不可能的?

【问题讨论】:

  • 如果去掉.jar,你的程序就不能引用里面的变量或方法。您所说的“有什么出路或者这是不可能的”是什么意思?
  • @CloseVoters,我认为这里的问题很清楚。

标签: java classloader


【解决方案1】:

您是否尝试使用 jar 编译它作为编译的依赖项。

然后在运行时,您将有一部分检查是否需要 jar,如果需要,您可以动态获取 jar 并像这样加载它(代码当然不能像这样工作;)):

import java.lang.reflect.Method;
import java.net.URLClassLoader;

Method addURL = null;
try {
    addURL = URLClassLoader.class.getDeclaredMethod("addURL",
            new Class[]{URL.class});
} catch (Exception e1) {
    //Log error
}
addURL.setAccessible(true);
//Maybe download the file or check if file exist else give out error and end processing
File yourJar = new File(filePath+"/"+fileName+".jar");
//Replace Your.Main.Class with your main class
addURL.invoke(Your.Main.Class.class
                        .getClassLoader(), yourJar.toURI().toURL());
// Your class should now be loaded and no more ClassNotFound exception should occur when it is accessed, but not if it is accessed before!

【讨论】:

    【解决方案2】:

    问题是你很难连接你的依赖。所以你的代码需要为第三方库做一些imports。您需要的是松散地耦合第三方库,以便您的应用程序的核心不需要导入任何与第三方库相关的内容。使用定义一个方法或一组方法的接口,以生成任何格式的报告。将此接口作为核心应用程序的一部分。然后,特定于格式的实现在依赖于您的核心应用程序和第 3 方库的单独模块中进行。在核心应用程序中使用工厂在运行时使用反射加载特定实现。如果请求的格式在类路径中不存在相关模块 jar,则会抛出 ClassNotFoundException,捕获并相应地处理。

    这里是您的应用程序的示例结构

    核心应用

    class ReportData {
    
    }   
    
    interface ReportGenerator {
        byte[] generate(ReportData data);
    }
    
    
    class ReportGeneratorFactory {
        public ReportGenerator getInstance(String format) 
                throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            ReportGenerator reportGenerator = null;
            if("txt".equals(format)) {
                reportGenerator = (ReportGenerator) 
                        Class.forName("com.foo.TxtReportGenerator").newInstance();
            } else if("html".equals(format)) {
                reportGenerator = (ReportGenerator) 
                        Class.forName("com.foo.HtmlReportGenerator").newInstance();
            } else if("xl".equals(format)) {
                reportGenerator = (ReportGenerator) 
                        Class.forName("com.foo.XlReportGenerator").newInstance();
            } else {
                throw new UnsupportedOperationException(
                     String.format("Unsupport format %s", format));
            }
            return reportGenerator;
        }
    }
    

    Txt / Html 导出(如果不需要第 3 方库,可以作为核心应用程序的一部分)

    class TxtReportGenerator implements ReportGenerator {
        public byte[] generate(ReportData data) {
            // TODO Auto-generated method stub
            return null;
        }
    }
    
    class HtmlReportGenerator implements ReportGenerator {
        public byte[] generate(ReportData data) {
            // TODO Auto-generated method stub
            return null;
        }
    }
    

    用于 XL 报告的模块(自己的 jar)(取决于您的核心应用程序和第 3 方库)

    class XlReportGenerator implements ReportGenerator {
        public byte[] generate(ReportData data) {
            // TODO Auto-generated method stub
            return null;
        }
    }
    

    用法:

    public static void main(String[] args) 
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        byte[] report = new ReportGeneratorFactory()
            .getInstance("xl")
            .generate(new ReportData());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-20
      • 1970-01-01
      • 1970-01-01
      • 2019-02-21
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多