Spring在切换到JPMS(Java平台模块系统)时出现NoSuchBeanDefinitionException错误。

huangapple go评论75阅读模式
英文:

Spring NoSuchBeanDefinitionException when switching to JPMS (Java Platform Module System)

问题

我正在尝试将一个大型项目迁移到JPMS(Java平台模块系统)。

其中包含一些Spring组件,它们给我带来了一些麻烦。
我创建了一个test repo来演示这个问题。当我删除module-info.java文件时,它可以正常工作,就像TestControllerTest.java中的测试所示。然而,如果我添加module-info.java,那么它就停止工作,并显示以下异常:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'RESTConfiguration': Unsatisfied dependency expressed through field 'fooAuthenticationProvider'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spacemetric.spring.jpmstest.auth.FooAuthenticationProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at spring.beans@5.2.6.RELEASE/org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at spring.beans@5.2.6.RELEASE/org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
at … 

堆栈跟踪似乎表明ApplicationContext无法找到@Autowired实现。我已经为深度反射打开了整个模块。我非常不确定,但我猜想这可能与classpath与modulepath有关,但我不知道该怎么做。

module-info.java文件如下:

open module com.spacemetric.spring.jpmstest {    	
	requires spring.core;
	requires spring.context;
	requires spring.beans;
	requires spring.security.config;
	requires spring.security.web;
	requires spring.webmvc;
	requires spring.security.core;
	requires javax.servlet.api;
	requires spring.web;
}

以下是Eclipse用于运行测试的命令行(如请求所示):

> C:\Program
> Files\Java\java-11-openjdk-11.0.7.10-1.windows.redhat.x86_64\bin\javaw.exe
> -ea --add-opens com.spacemetric.spring.jpmstest/com.spacemetric.spring.jpmstest=ALL-UNNAMED
> --add-modules=ALL-MODULE-PATH -Dfile.encoding=UTF-8 -p "C:\dev\source\spring-jpms-test\target\classes;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-core\5.2.6.RELEASE\spring-core-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\security\spring-security-web\5.3.2.RELEASE\spring-security-web-5.3.2.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\security\spring-security-core\5.3.2.RELEASE\spring-security-core-5.3.2.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-beans\5.2.6.RELEASE\spring-beans-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-context\5.2.6.RELEASE\spring-context-5.2.6.RELEASE.jar;C:\Users\Oscar Haglund.m2\repository\org\springframework\spring-web\5.2.6.RELEASE\spring-web-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\security\spring-security-config\5.3.2.RELEASE\spring-security-config-5.3.2.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-webmvc\5.2.6.RELEASE\spring-webmvc-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\javax\servlet\javax.servlet-api\3.1.0\javax.servlet-api-3.1.0.jar"
> -classpath "C:\Users\Oscar Haglund.m2\repository\org\springframework\spring-jcl\5.2.6.RELEASE\spring-jcl-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-aop\5.2.6.RELEASE\spring-aop-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-expression\5.2.6.RELEASE\spring-expression-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.7.0\junit-jupiter-engine-5.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\apiguardian\apiguardian-api\1.1.0\apiguardian-api-1.1.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\platform\junit-platform-engine\1.7.0\junit-platform-engine-1.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\platform\junit-platform-commons\1.7.0\junit-platform-commons-1.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\jupiter\junit-jupiter-api\5.7.0\junit-jupiter-api-5.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-test\5.2.6.RELEASE\spring-test-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m

英文:

I am trying to migrate a large project to JPMS (Java Platform Module System).

It contains some Spring components that are giving me some trouble.
I have created a test repo to demonstrate the issue. When I remove the module-info.java file it works just fine as shown by the test in TestControllerTest.java. However, if I add the module-info.java then it stops working with the following exception:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'RESTConfiguration': Unsatisfied dependency expressed through field 'fooAuthenticationProvider'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spacemetric.spring.jpmstest.auth.FooAuthenticationProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at spring.beans@5.2.6.RELEASE/org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at spring.beans@5.2.6.RELEASE/org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
at … 

The stack trace seems to indicate that the ApplicationContext is unable to find the @Autowired implementation. I have opened the entire module for deep reflection. My highly uneducated guess is that this might be related to the classpath versus modulepath but I am at a loss for what to do about it.

The module-info.java file is as follows:

open module com.spacemetric.spring.jpmstest {    	
	requires spring.core;
	requires spring.context;
	requires spring.beans;
	requires spring.security.config;
	requires spring.security.web;
	requires spring.webmvc;
	requires spring.security.core;
	requires javax.servlet.api;
	requires spring.web;
}

The following is the command line used by Eclipse to run the test (as requested):

> C:\Program
> Files\Java\java-11-openjdk-11.0.7.10-1.windows.redhat.x86_64\bin\javaw.exe
> -ea --add-opens com.spacemetric.spring.jpmstest/com.spacemetric.spring.jpmstest=ALL-UNNAMED
> --add-modules=ALL-MODULE-PATH -Dfile.encoding=UTF-8 -p "C:\dev\source\spring-jpms-test\target\classes;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-core\5.2.6.RELEASE\spring-core-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\security\spring-security-web\5.3.2.RELEASE\spring-security-web-5.3.2.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\security\spring-security-core\5.3.2.RELEASE\spring-security-core-5.3.2.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-beans\5.2.6.RELEASE\spring-beans-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-context\5.2.6.RELEASE\spring-context-5.2.6.RELEASE.jar;C:\Users\Oscar Haglund.m2\repository\org\springframework\spring-web\5.2.6.RELEASE\spring-web-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\security\spring-security-config\5.3.2.RELEASE\spring-security-config-5.3.2.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-webmvc\5.2.6.RELEASE\spring-webmvc-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\javax\servlet\javax.servlet-api\3.1.0\javax.servlet-api-3.1.0.jar"
> -classpath "C:\Users\Oscar Haglund.m2\repository\org\springframework\spring-jcl\5.2.6.RELEASE\spring-jcl-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-aop\5.2.6.RELEASE\spring-aop-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-expression\5.2.6.RELEASE\spring-expression-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.7.0\junit-jupiter-engine-5.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\apiguardian\apiguardian-api\1.1.0\apiguardian-api-1.1.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\platform\junit-platform-engine\1.7.0\junit-platform-engine-1.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\platform\junit-platform-commons\1.7.0\junit-platform-commons-1.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\jupiter\junit-jupiter-api\5.7.0\junit-jupiter-api-5.7.0.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\spring-test\5.2.6.RELEASE\spring-test-5.2.6.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\org\springframework\restdocs\spring-restdocs-mockmvc\2.0.5.RELEASE\spring-restdocs-mockmvc-2.0.5.RELEASE.jar;C:\Users\Oscar Haglund.m2\repository\org\springframework\restdocs\spring-restdocs-core\2.0.5.RELEASE\spring-restdocs-core-2.0.5.RELEASE.jar;C:\Users\Oscar
> Haglund.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.5\jackson-databind-2.9.5.jar;C:\Users\Oscar
> Haglund.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;C:\Users\Oscar
> Haglund.m2\repository\com\fasterxml\jackson\core\jackson-core\2.9.5\jackson-core-2.9.5.jar;C:\Users\Oscar
> Haglund.m2\repository\org\mockito\mockito-junit-jupiter\3.5.10\mockito-junit-jupiter-3.5.10.jar;C:\Users\Oscar
> Haglund.m2\repository\org\mockito\mockito-core\3.5.10\mockito-core-3.5.10.jar;C:\Users\Oscar
> Haglund.m2\repository\net\bytebuddy\byte-buddy\1.10.13\byte-buddy-1.10.13.jar;C:\Users\Oscar
> Haglund.m2\repository\net\bytebuddy\byte-buddy-agent\1.10.13\byte-buddy-agent-1.10.13.jar;C:\Users\Oscar
> Haglund.m2\repository\org\objenesis\objenesis\3.1\objenesis-3.1.jar;C:\Users\Oscar
> Haglund.m2\repository\org\junit\platform\junit-platform-launcher\1.7.0\junit-platform-launcher-1.7.0.jar;C:\dev\eclipse\configuration\org.eclipse.osgi\259\0.cp;C:\dev\eclipse\configuration\org.eclipse.osgi\257\0.cp"
> --patch-module "com.spacemetric.spring.jpmstest=C:\dev\source\spring-jpms-test\target\test-classes"
> --add-reads com.spacemetric.spring.jpmstest=ALL-UNNAMED org.eclipse.jdt.internal.junit.runner.RemoteTestRunner -version 3
> -port 55245 -testLoaderClass org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader
> -loaderpluginname org.eclipse.jdt.junit5.runtime -classNames com.spacemetric.spring.jpmstest.TestControllerTest

答案1

得分: 1

首先,将 module-info.java 放在 src/main/java 中,而不是 src/test/java 中。此外,我稍微修改了它:

module spring.jpms.test {
    requires spring.core;
    requires spring.context;
    requires spring.beans;
    requires spring.security.config;
    requires spring.security.web;
    requires spring.webmvc;
    requires spring.security.core;
    requires javax.servlet.api;
    requires spring.web;

    opens com.spacemetric.spring.jpmstest;
}

但是,无论如何,这只解决了部分问题,因为:

欢迎来到“模块”和“Spring”(或一般工具)的相当原始的现实。在这里可以看到有相同问题的人们。我找到的唯一可行的解决方案是:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <useModulePath>false</useModulePath>
    </configuration>
</plugin>

这适用于 mvn clean install(以及 junit5),我还没有尝试过或充分使用 intellij 使其工作。

英文:

First of all put the module-info.java in src/main/java, not in src/test/java. Also I have slightly changed it to:

module spring.jpms.test {
   requires spring.core;
   requires spring.context;
   requires spring.beans;
   requires spring.security.config;
   requires spring.security.web;
   requires spring.webmvc;
   requires spring.security.core;
   requires javax.servlet.api;
   requires spring.web;

   opens com.spacemetric.spring.jpmstest;

}

But anyway, this solves only "partially" because:

Welcome to a rather crude reality of modules and spring (or tools in general). Have a look here, where people have the same problems. The only viable solution I found is to do :

&lt;plugin&gt;
	&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
	&lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
	&lt;version&gt;3.0.0-M5&lt;/version&gt;
	&lt;configuration&gt;
		&lt;useModulePath&gt;false&lt;/useModulePath&gt;
	&lt;/configuration&gt;
&lt;/plugin&gt;

This works with mvn clean install (and junit5), I haven't tried or played enough with intellij to make it work.

huangapple
  • 本文由 发表于 2020年10月2日 22:20:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/64173160.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定