java - 奇怪的 Tomcat 8 部署行为

标签 java spring tomcat

当我将我的 Spring 4.0.1.RELEASE Web 应用程序部署到安装在 ext3 上的 Tomcat 8.0.33 上时,在 Centos 6.7 上运行 Java 1.8.0_92,我收到以下错误:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'qualityAuditTokenService' defined in URL [jar:file:/home/www/webapps/ROOT/WEB-INF/lib/product-service-2.0.1-SNAPSHOT.jar!/com/company/product/services/QualityAuditTokenService.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.company.workflow.dao.TokenDao]: : No qualifying bean of type [com.company.workflow.dao.TokenDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.company.workflow.dao.TokenDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:742)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1114)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1017)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4811)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5251)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
    at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1092)
    at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1834)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.company.workflow.dao.TokenDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1100)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:806)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:734)
    ... 28 more

但是,如果我在 Centos 6.7 上安装与 Tomcat 8.0.33 完全相同的 Web 应用程序,该应用程序安装在运行在 Java 1.8.0_92 上的 NFS 挂载上,它就可以正常工作。如果我将它安装到 Centos 上 ext3 上的 Tomcat 7.0.69、Ubuntu 上 ext4 上的 Tomcat 8.0.33 和 Windows 上的 NTFS,它也能正常工作。所以它只是在 Centos 上的 ext3 上的 Tomcat 8.0.33 中运行时抛出这个错误。如果这不是我们的实时部署环境,问题就不会太大。

所以这显然不是标准的“缺少注释”或“JAR 中缺少 bean 类”类型的问题,尽管我很高兴听到这方面的建议,以防我遗漏了什么。

此部署的奇怪之处在于 Spring bean 在不同的文件系统上以不同的顺序创建。在可用的版本中,以下内容出现在 Spring 日志记录最大化的日志文件中:

DEBUG DefaultListableBeanFactory:449 - Creating instance of bean 'tokenDaoHbm'
DEBUG DefaultListableBeanFactory:249 - Returning cached instance of singleton bean 'sessionFactory'
DEBUG DefaultListableBeanFactory:249 - Returning cached instance of singleton bean 'searchSessionFactory'
DEBUG DefaultListableBeanFactory:750 - Autowiring by type from bean name 'tokenDaoHbm' via constructor to bean named 'sessionFactory'
DEBUG DefaultListableBeanFactory:523 - Eagerly caching bean 'tokenDaoHbm' to allow for resolving potential circular references
DEBUG DefaultListableBeanFactory:249 - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
DEBUG DefaultListableBeanFactory:249 - Returning cached instance of singleton bean 'org.springframework.cache.config.internalCacheAdvisor'
DEBUG AnnotationTransactionAttributeSource:108 - Adding transactional method 'TokenDaoHbm.update' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG InfrastructureAdvisorAutoProxyCreator:551 - Creating implicit proxy for bean 'tokenDaoHbm' with 0 common interceptors and 1 specific interceptors
DEBUG JdkDynamicAopProxy:117 - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.company.product.dao.hibernate.TokenDaoHbm@4a51d9f9]
DEBUG DefaultListableBeanFactory:477 - Finished creating instance of bean 'tokenDaoHbm'

这是满足依赖关系的 bean,如果它被创建 - 在抛出异常的版本中,这个 bean 的创建是值得注意的,因为它不存在。

长话短说

那么,操作系统、文件系统类型和/或网络延迟如何改变 Spring 创建 bean 的顺序(或以其他方式破坏它的依赖性分析)?这肯定是 WAR 文件(以及与它一起打包的 Spring 版本)中的内容?

我试图通过@ComponentScan 和@Qualifier 影响 bean 的创建,但没有成功——还有其他方法吗?

这个问题与下面链接的问题很相似,但没有发布解决方案(他们遇到的问题是 Tomcat 7 而不是 8)。 Need help debugging Tomcat 7 application error

非常感谢任何帮助,因为这个真的让我很烦恼! :-D

最佳答案

我现在有一个解决方案(因此发布了一个答案)但是它很糟糕而且我仍然没有解释为什么这是必要的(所以我将保存接受的勾号以获得更优雅的解决方案或完整的解释).

原来我的问题与 ASF bugzilla 上提出的问题 57129 有关: https://bz.apache.org/bugzilla/show_bug.cgi?id=57129

但是,在此处概述的情况下,WAR 中的多个 JAR 文件包含同一类文件的不同版本。这意味着更改顺序将更改应用程序行为 - 这是不可取的。

在我的例子中,有问题的类 TokenDaoHbm 在 WAR 文件中只存在一次。只是,如果 Tomcat 类加载器在 Spring 开始实例化 qualityAuditTokenService bean 时还没有加载 product-dao-hibernate-2.0.1-SNAPSHOT JAR 文件,那么您将得到一个 NoSuchBeanDefinitionException。 Spring 和/或 Tomcat 一定知道在 bean 实例化开始之前必须加载所有类吗?

因此,为了解决我的问题,我根据 Mark Thomas 在 ASF 错误帖子中的建议,将以下内容放入 WAR 的应用程序 context.xml 中:

<Resources>
  <PreResources className="org.apache.catalina.webresources.FileResourceSet"
                base="${catalina.base}/webapps/ROOT/WEB-INF/lib/product-dao-hibernate-2.0.1-SNAPSHOT.jar"
                webAppMount="/WEB-INF/lib/product-dao-hibernate-2.0.1-SNAPSHOT.jar" />
</Resources>

如果有人可以进一步阐明这一点,我很乐意将其标记为已接受的答案。

关于java - 奇怪的 Tomcat 8 部署行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36862312/

相关文章:

linux - 使用 snmp 监控部署在 Tomcat 中的 J2EE 应用程序

java - 尝试与 startwith 匹配时类强制转换异常

java - spring 中的 org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException

java - org.glassfish.jersey.server.internal.process.MappableException : org. apache.catalina.connector.ClientAbortException : java.net.SocketException:

java - 使用 spring-web.jar 获取 java.lang.ClassNotFoundException : org. springframework.web.filter.DelegatingFilterProxy

Spring SAML - 如何在 SP HTTP 请求中添加自定义字段?

tomcat - support.PluginAwareResourceBundleMessageSource 无法解析插件的任何资源

java - 根据 jframe 中的条件在特定区域上绘制颜色

java - ejb 3.1 中的计时器服务 - 安排调用超时问题

Java - 使用 Swing GUI 运行 Web 应用程序