0

对于独立的 java 应用程序,我可以使用以下代码在运行时根据库路径动态加载 jar lib。如果我在 Java Web 容器中部署相同的代码并作为 servlet 运行,它似乎不起作用。我实际上希望能够根据 servlet 请求中的 jar 库路径加载不同的 jar 库。

这意味着单个 servlet 必须能够在运行时动态加载不同的 jar 库并运行向前的 biz 逻辑

user1 可能会请求在 /tmp/lib/v1.0/ .jar下加载 jar 文件
user2 可能会请求在 /tmp/lib/v1.1/
.jar下加载 jar 文件
(v1.0 和 v1.1 中的 jar 文件得到完全相同的类名)

谢谢!!!

=== 主要 ==============

LibraryLoader loader = new LibraryLoader();
loader.addClassPath(<jar lib root path>);

// below will run biz logic

=== LibraryLoader.java ==========

public class LibraryLoader {

    URLClassLoader urlClassLoader;

    public LibraryLoader() {
        urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
    }

    public void addClassPath(String jarLibPath) throws Exception {
        Class urlClass = URLClassLoader.class;
        File jarPath = new File(jarLibPath);

        FileFilter jarFilter = new FileFilter() {
            public boolean accept(File f) {
                if (f.isDirectory())
                    return true;
                String name = f.getName().toLowerCase();
                return name.endsWith("jar");
            }
        };

        File[] files = jarPath.listFiles(jarFilter);
        for (File file : files) {
            if (file.isFile()) {
                URI uriPath = file.toURI();
                URL urlPath = uriPath.toURL();
                Method method = urlClass.getDeclaredMethod("addURL", new Class[] { URL.class });
                method.setAccessible(true);
                method.invoke(urlClassLoader, new Object[] { urlPath });
                System.out.println(file.getCanonicalPath());
            } else {
                addClassPath(file.getCanonicalPath());
            }
        }
    }
}
4

2 回答 2

0

那不是你想做的。即使在您的独立程序中,这也不会真正起作用(因为您可能会将同一个 jar 的多个版本推送到主类加载器中)。您要做的是创建一个包含新 jar 的新类加载器,然后在新类加载器中调用某个类。

例如:

// get relevant jar urls
URL[] urls = ...;

ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
try {
  URLClassLoader loader = new URLClassLoader(urls);
  Thread.currentThread().setContextClassLoader(loader);

  Class<?> entryClass = loader.loadClass("entry.class.name");
  // do something here w/ entryClass (e.g. instantiate it) ...

} finally {
  Thread.currentThread().setContextClassLoader(oldLoader);
}

当然,您可能希望缓存这些类加载器并在后续请求中重新使用它们。

当然,我不确定您为什么不使用不同版本的 jar 部署多个版本的 servlet(因为您指出该版本是 servlet 路径的一部分)。

于 2012-06-26T04:36:45.750 回答
0

您应该为不同的用户创建不同的类加载器并设置为当前线程。

ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
ClassLoader currentLoader;
if(user1){
   //initialize classloader with jar files under /tmp/lib/v1.0/.jar
   currentLoader  = user1ClassLoader;
} else if(user2){
   //initialize classloader with jar files under /tmp/lib/v1.1/.jar
   currentLoader  = user2ClassLoader;
}
Thread.currentThread().setContextClassLoader(currentLoader  );

//invoke business logic

//reset the actual loader
Thread.currentThread().setContextClassLoader(ctxLoader );
于 2012-06-26T04:47:03.660 回答