【问题标题】:Spring-boot @ComponentScan not working when classes are packaged in a jar, working fine when classes are not packaged将类打包在 jar 中时 Spring-boot @ComponentScan 不起作用,未打包类时工作正常
【发布时间】:2021-08-31 01:29:05
【问题描述】:
  • 春季版:5.3.9
  • Spring-boot 版本:2.5.3

这是我的类和包的层次结构示例:

my.app
   - MyApplication.class
     .data
      - MyDataRelatedComponent.class
     .service
      - MyServiceRelatedComponent.class
      

MyApplication 有@SpringBootApplication,其他类有@Service、@Component 等,这是我的目录结构:

/myapp/config/
      /libs/

application.yml 位于 /myapp/config/ 中,我的应用所依赖的 jar 文件都位于 /libs 中。

当我使用 Eclipse 的 JAR EXPORT 将我的类打包到一个 jar 中并在 /myapp/libs 中找到它然后按如下执行时,Spring 不会扫描任何 bean 候选类。它不起作用。

java -cp /myapp/config:/myapp/libs/* my.app.MyApplication

当我创建目录 /myapp/classes 并在此处找到我的类然后执行如下操作时,Spring 会扫描我的 bean 候选类。它工作正常。

java -cp /myapp/classes:/myapp/config:/myapp/libs/* my.app.MyApplication
   

经过几个小时的互联网研究,我认为如果我使用 spring-boot-maven-plugin 会解决,但是由于我公司的安全政策,我不能使用 Maven。现在我不仅想执行我的应用程序,我还想知道确切的问题是什么。

我认为这是一个与 classpath 相关的问题。我错过了什么?

【问题讨论】:

  • #1 你至少在使用 maven 吗?您的主要问题是缺少 spring-boot-maven-plugin。 #2 构建和运行 spring-boot 构建插件听起来很有趣 #3 你的 libs 文件夹中有所有必需的 spring jar 吗? #4 如果可以的话,能否告诉我们安全警察背后的原因。互联网访问是否受到限制?
  • @JRichardsz #1 我不能像我提到的那样使用 maven。 #3 我有所有需要的 jar 文件。如果不是,则无论类是否为包,它都可能无法正确运行。当类没有打包时它工作得很好。 #4 是的,公司的构建环境不允许上网。
  • 是否有机会与所有 Maven 格式的 jar 共享整个 .m2 文件夹? Maven 提供了一个选项来做到这一点,只是为了你的情况!如果使用 maven 对你来说是不可能,我认为 maven 之父是给你的:ant framework
  • @JRichardsz 我不明白你为什么在谈论 Maven。 Maven 不是我可以采取的选择。这里没有专家。正如我在上面的问题中提到的那样,这不仅仅是为了执行我的应用程序,而是要确切地知道它为什么不能工作。如果我只想执行我的应用程序,我只会使用类,而不是 jar 包装。这是执行我的应用程序的最简单的解决方案。
  • @JRichardsz 和 maven 一样,我不需要 Ant,因为我已经拥有了我需要的所有依赖 jar。 Eclipse 或 javac 足以构建我的应用程序并且实际上工作正常。

标签: java spring spring-boot


【解决方案1】:

我发现了问题所在。我认为这不是一个完整的答案,但很接近。

Spring 使用 PathMatchingResourcePatternResolver 扫描资源,并且此类在内部尝试使用 ResourceLoader 的 ClassLoader.getResources 或有条件的 ClassLoader.getSystemResources 获取资源>“my/app”,MyApplication类所在的位置,是我的Spring boot应用的起点。

PathMatchingResourcePatternResolver.doFineAllClassPathResources的源码如下:

ClassLoader cl = getClassLoader();  // Internal ResourceLoader's ClassLoader
Enumeration<URL> resourceUrls = (cl != null) ? cl.getResources(path) : ClassLoader.getSystemResources(path);

当使用未打包的类执行应用程序时,resourceUrls 包含给定路径的绝对文件系统路径,“my/app”,但是当使用打包的类时一个 jar,它会导致一个空的枚举,并且 Spring 不会扫描我位于 my.app 的子包中的任何类。

这不是春天的事。我试图用没有 Spring 的非常简单的示例 Java 代码来重现它,如下所示:

resourcesUrls = Test.class.getClassLoader().getResources("my/app");
...
resourcesUrls = ClassLoader.getSystemResources("my/app");
...

结果与 Spring 的结果相同。这是因为当打包在 jar 中时,类不再是独立文件,它们是二进制文件。如果我想读取 jar 文件中的资源,我需要使用 ClassLoader.getResourceAsStream

我认为 Spring Boot 应用程序不打算以这种方式打包。我想 Spring 对此有自己的技术解决方案,这也是应该使用 Maven 或 Gradle 插件来打包 Spring 启动应用程序的原因之一。

【讨论】:

    猜你喜欢
    • 2016-11-23
    • 1970-01-01
    • 2014-09-10
    • 2015-02-21
    • 2017-03-26
    • 1970-01-01
    • 2017-02-17
    • 2014-05-07
    • 2015-06-10
    相关资源
    最近更新 更多