Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/331.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 Spring类路径资源FileNotFoundException的原因_Java_Tomcat_Classpath_Embedded Resource - Fatal编程技术网

Java Spring类路径资源FileNotFoundException的原因

Java Spring类路径资源FileNotFoundException的原因,java,tomcat,classpath,embedded-resource,Java,Tomcat,Classpath,Embedded Resource,我的web应用程序使用Spring 4.3.5。我们需要从jar本身加载一个存储在jar类路径中的Freemarker模板 让我尽量概括我的场景(稍后我将提供代码) 罐式结构 src /com/acme/package/ComponentUsingResource.java META-INF 资源 template1.ftl.html template1.ft2.html jar包含在WAR应用程序中的WEB-INF/lib中 在ComponentUsingResource.ja

我的web应用程序使用Spring 4.3.5。我们需要从jar本身加载一个存储在jar类路径中的Freemarker模板

让我尽量概括我的场景(稍后我将提供代码)

罐式结构

  • src
    • /com/acme/package/ComponentUsingResource.java
  • META-INF
    • 资源
      • template1.ftl.html
      • template1.ft2.html
jar包含在WAR应用程序中的WEB-INF/lib中

在ComponentUsingResource.java中,我使用以下语句加载资源:
newclasspathresource(“META-INF/templates/template1.ftl.html”).getInputStream()

同样的WAR应用程序可以在我的笔记本电脑(JDK 8 121,Tomcat 8.0.43)、我们的SIT环境(JDK 8>100,Tomcat 8.0.39)和安装在笔记本电脑上的Tomcat 8.0.36上运行,但在我们的客户站点(JDK 8 96,Tomcat 8.0.36)上无法运行。加载ClasspathResource时出现FileNotFoundException,因此无法工作

当应用程序启动时,一系列@Autowired依赖项进入我基于资源的bean的初始化

    Arrays.asList("ftt-mail-natixclose-it", "ftt-mail-natixflussi-it", "ftt-mail-processreport-en", "ftt-mail-processreport-it",
                  "ftt-mail-regclosed-en", "ftt-mail-regclosed-it", "ftt-mail-regnotclosed-multi-en", "ftt-mail-regnotclosed-multi-it",
                  "ftt-mail-regnotclosed-single-en", "ftt-mail-regnotclosed-single-it", "ftt-mail-timestamps-en", "ftt-mail-timestamps-it",
                  "ftt-mail-missingdata-multi-en", "ftt-mail-missingdata-multi-it", "ftt-mail-missingdata-single-en",
                  "ftt-mail-missingdata-single-it", "ftt-mail-natixflussi-it")
          .parallelStream().forEach(templateName -> {

              ClassPathResource classpathResource = new ClassPathResource("META-INF/templates/" + templateName + ".ftl.html");
              try (Reader reader = new InputStreamReader(classpathResource.getInputStream(), Charset.forName("utf-8")))
              {
                  freemarker.template.Template tmpl = new freemarker.template.Template(templateName, reader, configuration);
                  cacheTemplate.put(templateName, tmpl);
              }
              catch (IOException e)
              {
                  throw new RuntimeException("Errror processing template " + templateName, e);
              }

          });
我知道,在没有适当的Java同步的情况下,从
ParallelStream
写入缓存是有问题的做法,这将在后面讨论

问题是,在所有这些资源中,代码找不到一个:“ftt mail regclosed en.ftl.html”。它将资源装载到除客户座位以外的任何地方。由于这是一个并行流,我可能猜这是唯一令人不快的资源

根异常是:
java.io.FileNotFoundException:class路径资源[META-INF/templates/ftt mail regclosed en.ftl.html]无法打开,因为它不存在

我无法提供完整的堆栈跟踪,因为我无法在这里复制和粘贴片段

我已经三次检查了jar文件的内容,所有预期的资源都已准备就绪。我要求客户(记住,WARs是二进制相同的!)进行相同的检查,但他们没有将其解包,而是向我提供了jar文件的部分二进制转储的屏幕截图,在那里我可以看到文件名

我知道该应用程序已由Black Duck scanner针对软件漏洞进行处理。它经常报告可疑的依赖关系,但我(或客户)没有关于Black Duck剥离资源的证据或知识。我这样说是因为在我们的线程中,一名技术人员怀疑BD可能从包中剥离了一个资源。对我来说不太可能

我可以采取哪些其他步骤来调查此问题?是什么原因仅在单个环境中导致这样的FileNotFoundException?
请注意,这非常重要:早期版本的软件的其他部分使用了非常相同的语法
newclasspathResource(“META-INF/something”)
。上一个版本包含这种加载资源的方法,运行良好。这意味着它从包中嵌入的其他JAR加载了自己的类路径资源这是一个潜在的答案。我无法重现这个问题

当您使用Spring调用
newclasspathResource
时,您没有设置类加载器。我假设Spring使用了系统类加载器(
classloader.getSystemClassLoader()

错。Spring使用一个内部实用程序方法来获取绑定到线程的当前上下文的类加载器。可能由于我不知道的原因,绑定到bean初始化方法的类加载器(碰巧是apachetomcat赞助的
WebApplicationClassLoader
)与系统类加载器不同

实际上,Oracle系统类加载器无法从Jar文件加载资源。至少因为我自己调试并找到了答案

也许,我说,Maybe,删除并行性并且不节省2秒的一次性启动处理,使Lambda表达式能够获得web应用程序类加载器实例,而不是Oracle JDK

然而,这并不能解释为什么这种情况只发生在客户现场,而不是我们所有的环境中,包括PROD


解决方案2是显式地将
getClass().getClassLoader()
传递给ClassPathResource的构造函数这是一个可能的答案。我无法重现这个问题

当您使用Spring调用
newclasspathResource
时,您没有设置类加载器。我假设Spring使用了系统类加载器(
classloader.getSystemClassLoader()

错。Spring使用一个内部实用程序方法来获取绑定到线程的当前上下文的类加载器。可能由于我不知道的原因,绑定到bean初始化方法的类加载器(碰巧是apachetomcat赞助的
WebApplicationClassLoader
)与系统类加载器不同

实际上,Oracle系统类加载器无法从Jar文件加载资源。至少因为我自己调试并找到了答案

也许,我说,Maybe,删除并行性并且不节省2秒的一次性启动处理,使Lambda表达式能够获得web应用程序类加载器实例,而不是Oracle JDK

然而,这并不能解释为什么这种情况只发生在客户现场,而不是我们所有的环境中,包括PROD


解决方案2是显式地将
getClass().getClassLoader()
传递给ClassPathResource的构造函数

您将资源置于META-INF下的原因是什么?如果类的结构相同,则可以执行Thread.currentThread().getContextClassLoader().getResourceAsStream(“myfile.txt”)。将代码与