在运行时加载jar并使用它的类

时间:2014-09-24 10:13:03

标签: java classloader

我有一个问题,我需要一些帮助。

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

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

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

有没有出路或这是不可能的?

2 个答案:

答案 0 :(得分:0)

问题是你很难连接你的依赖项。因此,您的代码需要为第三方库执行一些import。您需要的是松散地耦合第三方库,以便您的应用程序的核心不需要导入与第三方库相关的任何内容。使用接口定义以任何格式生成报告所需的方法或方法集。使此接口成为核心应用程序的一部分。然后,格式特定的实现将在独立的模块中进行,这些模块依赖于您的核心应用程序和第三方库。使用核心应用程序中的工厂使用refelction在运行时加载特定实现。如果请求格式化类路径中不存在相关模块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导出(如果不需要第三方库,可能是核心应用程序的一部分)

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)(取决于您的核心应用程序和第三方库)

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());
}

答案 1 :(得分:0)

您是否尝试使用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!
相关问题