所以我的主项目中有一组子项目。第一个项目(在下面的示例中称为
mainCode
)实现了应用程序的全部功能。但是,WidgetAImpl
和WidgetBImpl
被分成单独的子项目,以便在需要修复时可以独立部署。 WidgetAImpl
和 WidgetBImpl
类与接口 WidgetInterface
位于同一个包中。
这是项目布局:
project
+ mainCode
+ /src/main/java/com/mycompany/myproject/Application.java
+ /src/main/java/com/mycompany/myproject/AppConfig.java
+ /src/main/java/com/mycompany/myproject/widgets/WidgetInterface.java
+ widgets
+ WidgetA
+ /src/main/java/com/mycompany/myproject/widgets/WidgetAImpl.java
+ WidgetB
+ /src/main/java/com/mycompany/myproject/widgets/WidgetBImpl.java
我用 gradle 构建这些项目,使
mainCode
项目成为我们的 war 文件,用于部署到 tomcat,每个小部件都会生成一个 jar 文件。目标是将 jar 文件添加到 tomcat 的类路径中,并单独部署 war 文件。我花了一天时间让 Gradle 通过声明 WidgetAImpl
项目为依赖项来构建 mainCode
项目。所以 Gradle 现在可以正确构建它们,并且我有一个 mainCode.war
和一个 WidgetAImpl.jar
以及一个 WidgetBImpl.jar
文件。在实现中,小部件都通过 Autowired HashMap 聚集在一起,以便在运行时在单个 HashMap 中创建所有实现的小部件。我已通过 catalina.properties sharedLoader 属性将小部件添加到 tomcat 的类路径中。
我的问题是,当我将 war 文件部署到 tomcat 时,出现以下错误(已修剪空间):
2017-11-15 21:55:39.841 WARN 16687 --- [nio-8443-exec-4] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.scheduling.annotation.ProxyAsyncConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [com.mycompany.myproject.widgets.WidgetAImpl] for bean with name 'WidgetAImpl' defined in URL [jar:file:/mycompany/libs/WidgetAImpl.jar!/com/mycompany/myproject/widgets/WidgetAImpl.class]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: com/mycompany/myproject/widgets/WidgetInterface
2017-11-15 21:55:39.845 ERROR 16687 --- [nio-8443-exec-4] o.s.b.f.s.DefaultListableBeanFactory : Destroy method on bean with name 'org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor' threw an exception
java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@3633386f: startup date [Wed Nov 15 21:55:38 UTC 2017]; root of context hierarchy
at org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster(AbstractApplicationContext.java:404) [spring-context-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.context.support.ApplicationListenerDetector.postProcessBeforeDestruction(ApplicationListenerDetector.java:97) ~[spring-context-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:253) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:578) [spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:554) [spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:954) [spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:523) [spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:961) [spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1033) [spring-context-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:555) [spring-context-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) [spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
...
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [com.mycompany.myproject.widgets.WidgetAImpl] for bean with name 'WidgetAImpl' defined in URL [jar:file:/mycompany/libs/WidgetAImpl.jar!/com/mycompany/myproject/widgets/WidgetAImpl.class]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: com/mycompany/myproject/widgets/WidgetInterface
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1364) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:639) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:607) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1456) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:420) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:390) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors(BeanFactoryUtils.java:220) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1243) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1164) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1089) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1059) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:663) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
... 68 common frames omitted
Caused by: java.lang.NoClassDefFoundError: com/mycompany/myproject/widgets/WidgetInterface
at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_144]
at java.lang.ClassLoader.defineClass(Unknown Source) ~[na:1.8.0_144]
at java.security.SecureClassLoader.defineClass(Unknown Source) ~[na:1.8.0_144]
at java.net.URLClassLoader.defineClass(Unknown Source) ~[na:1.8.0_144]
at java.net.URLClassLoader.access$100(Unknown Source) ~[na:1.8.0_144]
at java.net.URLClassLoader$1.run(Unknown Source) ~[na:1.8.0_144]
at java.net.URLClassLoader$1.run(Unknown Source) ~[na:1.8.0_144]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_144]
at java.net.URLClassLoader.findClass(Unknown Source) ~[na:1.8.0_144]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_144]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_144]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_144]
at java.lang.Class.forName(Unknown Source) ~[na:1.8.0_144]
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1271) ~[catalina.jar:8.5.20]
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119) ~[catalina.jar:8.5.20]
at org.springframework.util.ClassUtils.forName(ClassUtils.java:250) ~[spring-core-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:394) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1408) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1353) ~[spring-beans-4.3.4.RELEASE.jar:4.3.4.RELEASE]
... 79 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.mycompany.myproject.widgets.WidgetInterface
at java.net.URLClassLoader.findClass(Unknown Source) ~[na:1.8.0_144]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_144]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.8.0_144]
... 98 common frames omitted
(此处有完整的异常堆栈跟踪:https://pastebin.com/KwaNGaeN)
由此看来Spring找不到我的WidgetInterface。但是,我已经确认 WidgetInterface 类文件is 在 war 文件中。此外,它与 WidgetAImpl 和 WidgetBImpl 是相同的 java 包(即使它们位于单独的文件中)。为什么看不到WidgetInterface?
您可以使用
common
创建 base
或 WidgetInterface.java
模块吗?将其作为小部件添加到 Tomcat。然后所有其他罐子和战争都可以依赖那个公共部分。 Tomcat 将有干净的路径如何加载它,其他模块使用什么。
这在 IntelliJ IDE 中对我有用。
请在应用程序内创建文件夹作为 libs 并放入 jar。
repositories {
maven {
flatDir {
dirs "app/libs"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}