Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 扫描Embeded Tomcat中的清单类路径JAR_Java_Spring Boot_Servlet 3.0_Embedded Tomcat 8 - Fatal编程技术网

Java 扫描Embeded Tomcat中的清单类路径JAR

Java 扫描Embeded Tomcat中的清单类路径JAR,java,spring-boot,servlet-3.0,embedded-tomcat-8,Java,Spring Boot,Servlet 3.0,Embedded Tomcat 8,我有一个嵌入式Tomcat应用程序,它打包为一个可执行(瘦)jar,具有多个外部jar依赖项 构建过程生成一个META-INF/MANIFEST.MF,其中包含头字段Main Class和Class Path(每个运行时依赖项有一个条目) 我想使用一个简单的java-jar my_app.jar来执行应用程序,但是无法让Tomcat扫描这些依赖的jar(以便发现TLD或@handleType类,比如SpringWebApplicationInitializer) 我以这种方式配置jar扫描: S

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

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

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

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

StandardJarScanner jarScanner = (StandardJarScanner) ctx.getJarScanner();
jarScanner.setScanBootstrapClassPath(true);
jarScanner.setScanClassPath(true);
所有的JAR都有一个
META-INF
文件夹,但是扫描器完全忽略了它们

有什么想法吗

注意:我可以使用不同的方法(fatjar,从maven运行,…)来实现这一点,但我对以这种方式实现它感兴趣,就像任何其他java应用程序一样


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

当java应用程序作为
java-jar执行时,
URLClassLoader.getURLS()
不会返回类路径jar,因此系统类加载器会出现问题

见:

在上一篇文章中,建议使用反射来访问system classloader实例中的私有字段,但这会带来几个问题:

  • 安全管理员可以禁止此登录
  • 解决方案取决于实现
所以我想出了另一个办法:

  • 对于给定的类加载器,枚举所有可用的清单
    cl.getResources(“META-INF/manifest.MF”)
    。这些清单可以是由当前类加载器或其提升类加载器管理的JAR清单
  • 对其父类加载器执行相同的操作
  • 返回(1)中但不在(2)中的那些清单的JAR集
  • 该方法工作的唯一要求是类路径中的JAR必须有一个清单才能返回(要求不多)

    /**
    *返回URL的搜索路径,以加载
    *指定的类装入器,包括在
    *{@code Class path}可执行jar清单的头,在
    *类加载器是系统类加载器的情况。
    *
    *注意:这些最后的罐子不是由供应商退回的
    *{@link java.net.URLClassLoader#getURLs()}。
    *

    *@param cl *@返回 */ 公共静态URL[]获取URL(URLClassLoader cl){ 如果(cl.getParent()==null | |!(cl.getParent()) URLClassLoader的实例){ 返回cl.getURL(); } Set urlSet=new LinkedHashSet(); URL[]URL=cl.getURL(); URL[]urlsFromManifest=GetJarURLSFROMMANIFEST(cl); URLClassLoader parentCl=(URLClassLoader)cl.getParent(); URL[]ancestorUrls=getJarUrlsFromManifests(parentCl); for(int i=0;i
    Tomcat注册发行:

    /**
     * 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);
        }
    }