gpt4 book ai didi

java - 在嵌入式 Tomcat 中扫描 list 类路径 jar

转载 作者:行者123 更新时间:2023-11-30 08:04:06 24 4
gpt4 key购买 nike

我有一个嵌入式 Tomcat 应用程序打包为一个可执行文件(瘦)jar,具有多个外部 jar 依赖项。

构建过程会生成一个 META-INF/MANIFEST.MF,其中包含 header 字段 Main-ClassClass-Path(带有一个条目每个运行时依赖项)。

我想使用一个简单的 java -jar my_app.jar 来执行应用程序,但是我无法让 Tomcat 扫描这些依赖的 jar(为了发现 TLD或 @HandlesTypes 类,如 Spring WebApplicationInitializer)。

我正在以这种方式配置 jar 扫描:

StandardJarScanner jarScanner = (StandardJarScanner) ctx.getJarScanner();
jarScanner.setScanBootstrapClassPath(true);
jarScanner.setScanClassPath(true);

并且所有的 jar 都有一个 META-INF 文件夹,但是扫描器完全忽略了它们。

有什么想法吗?

Note: I can make this work using different approaches (fat jar, running from maven, ...) but I am interested in making it work this way, as any other java application.

最佳答案

Tomcat 通过重复调用 URLClassLoader.getURLS() 获取要扫描的 jar URL在类加载器层次结构中(自下而上)

URLClassLoader.getURLS() 以来,系统类加载器出现了问题。当 java 应用程序作为 java -jar <executable-jar> 执行时不返回类路径 jar

参见:How does a classloader load classes reference in the manifest classpath?

在上一篇文章中建议使用反射来访问系统类加载器实例中的私有(private)字段,但这会带来几个问题:

  • 安全管理员可以禁止此加入
  • 解决方案取决于实现

所以我想出了另一种方法:

  1. 对于给定的类加载器,枚举所有可用的 list cl.getResources("META-INF/MANIFEST.MF") .这些 list 可以是当前类加载器或其上级类加载器管理的 jar。
  2. 对其父类加载器做同样的事情
  3. 返回在 (1) 中但不在 (2) 中的 jar 集

此方法工作的唯一要求是类路径中的 jar 必须具有 list 才能返回(要求不高)。

/**
* Returns the search path of URLs for loading classes and resources for the
* specified class loader, including those referenced in the
* {@code Class-path} header of the manifest of a executable jar, in the
* case of class loader being the system class loader.
* <p>
* Note: These last jars are not returned by
* {@link java.net.URLClassLoader#getURLs()}.
* </p>
* @param cl
* @return
*/
public static URL[] getURLs(URLClassLoader cl) {
if (cl.getParent() == null || !(cl.getParent()
instanceof URLClassLoader)) {
return cl.getURLs();
}
Set<URL> urlSet = new LinkedHashSet();
URL[] urLs = cl.getURLs();
URL[] urlsFromManifest = getJarUrlsFromManifests(cl);
URLClassLoader parentCl = (URLClassLoader) cl.getParent();
URL[] ancestorUrls = getJarUrlsFromManifests(parentCl);

for (int i = 0; i < urlsFromManifest.length; i++) {
urlSet.add(urlsFromManifest[i]);
}
for (int i = 0; i < ancestorUrls.length; i++) {
urlSet.remove(ancestorUrls[i]);
}
for (int i = 0; i < urLs.length; i++) {
urlSet.add(urLs[i]);
}
return urlSet.toArray(new URL[urlSet.size()]);
}

/**
* Returns the URLs of those jar managed by this classloader (or its
* ascendant classloaders) that have a manifest
* @param cl
* @return
*/
private static URL[] getJarUrlsFromManifests(ClassLoader cl) {
try {
Set<URL> urlSet = new LinkedHashSet();
Enumeration<URL> manifestUrls =
cl.getResources("META-INF/MANIFEST.MF");
while (manifestUrls.hasMoreElements()) {
try {
URL manifestUrl = manifestUrls.nextElement();
if(manifestUrl.getProtocol().equals("jar")) {
urlSet.add(new URL(manifestUrl.getFile().substring(0,
manifestUrl.getFile().lastIndexOf("!"))));
}
} catch (MalformedURLException ex) {
throw new AssertionError();
}
}
return urlSet.toArray(new URL[urlSet.size()]);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}

Tomcat注册问题:https://bz.apache.org/bugzilla/show_bug.cgi?id=59226

关于java - 在嵌入式 Tomcat 中扫描 list 类路径 jar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35922072/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com