1. 概述
org.springframework.beans.factory.BeanDefinitionStoreException
异常,是当 Bean 定义无效或加载该 Bean 出现问题导致。本文将讨论出现该异常的常见原因及其解决方法。
2. Cause: java.io.FileNotFoundException
导致 BeanDefinitionStoreException
的原因有很多种,原因之一是由于 IOException 导致,即文件找不到。下面我们将具体分析。
2.1. ServletContext XML解析IO异常
这通常发生在基于 Spring MVC 的项目中,在 web.xml 中设置 DispatcherServlet:
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
默认情况下,Spring 会在 /WEB-INF 目录下查找名为 springMvcServlet-servlet.xml 的配置文件。
如果此文件不存在,则会抛出以下异常:
org.springframework.beans.factory.BeanDefinitionStoreException:
Ioexception Parsing Xml Document from Servletcontext Resource [/WEB-INF/mvc-servlet.xml];
nested exception is java.io.FileNotFoundException:
Could not open ServletContext resource [/WEB-INF/mvc-servlet.xml]
所以,如果 mvc-servlet.xml 配置文件确实不存在,则可以创建一个。示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd" >
</beans>
2.2. 解析Class Path资源IO异常
这种问题一般是路径位置不对,或文件不存在。
对于Java 配置方式
@Configuration
@ImportResource("beans.xml")
public class SpringConfig {...}
对于XML配置方式
<import resource="beans.xml"/>
或通过代码手动创建 Spring XML 上下文:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
以上方式,如果文件不存在都会报下面的错:
org.springframework.beans.factory.BeanDefinitionStoreException:
Ioexception Parsing Xml Document from Servletcontext Resource [/beans.xml];
nested exception is java.io.FileNotFoundException:
Could not open ServletContext resource [/beans.xml]
解决方案 是把配置文件正确的放到 /src/main/resources 目录下,这样Spring 才能找到并使用它。
3. Cause: Could Not Resolve Placeholder …
当 Spring 尝试解析属性但无法解析时,会出现此错误——可能有多种原因。
我们一般通过 Java 注解的方式读取属性:
@Value("${some.property}")
private String someProperty;
或传统的XML:
... value="${some.property}" ...
那么,我们首先要检查引用的属性的名称是否与配置文件中的一致:
some.property=someValue
然后需要检测配置文件的路径是否正确,并被成功的Spring加载,一般放在 /src/main/resources
目录下。这里我们有一篇关于Spring属性文件的详细描述。
Spring 无法解析属性的另一个可能原因是 Spring 上下文中可能存在多个 PropertyPlaceholderConfigurer bean(或多个 property-placeholder 元素)
如果是这种情况,那么解决方案要么是将它们合并为一个,要么使用 ignoreUnresolvablePlaceholders 在父上下文中配置一个。
4. Cause: java.lang.NoSuchMethodError
此错误有多种形式,一种较常见的原因是:
org.springframework.beans.factory.BeanDefinitionStoreException:
Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/mvc-servlet.xml];
nested exception is java.lang.NoSuchMethodError:
org.springframework.beans.MutablePropertyValues.add (Ljava/lang/String;Ljava/lang/Object;)
Lorg/springframework/beans/MutablePropertyValues;
这通常发生在类路径上存在多个版本的 Spring 时。意外在项目类路径上包含较旧版本的 Spring 更常见——我在《Spring 安全与 Maven 文章》中描述了这个问题和解决方案:Spring 安全与 Maven 文档。
简而言之,此错误的解决方案很简单——检查类路径上的所有 Spring JAR,并确保它们都具有相同的版本——并且这个版本为 3.0 或更高版本。
同样,这个异常不限于 MutablePropertyValues 类——还有其他版本不一致引起的相同问题:
org.springframework.beans.factory.BeanDefinitionStoreException:
Unexpected exception parsing XML document from class path resource [/WEB-INF/mvc-servlet.xml];
- nested exception is java.lang.NoSuchMethodError:
org.springframework.util.ReflectionUtils.makeAccessible(Ljava/lang/reflect/Constructor;)V
5. Cause: java.lang.NoClassDefFoundError
这一般和Spring Maven 依赖项有关:
org.springframework.beans.factory.BeanDefinitionStoreException:
Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/mvc-servlet.xml];
nested exception is java.lang.NoClassDefFoundError:
org/springframework/transaction/interceptor/TransactionInterceptor
当在 XML 中配置事务时,会发生这种情况:
<tx:annotation-driven/>
NoClassDefFoundError
意味着 Spring 事务支持——即 spring-tx ——不在类路径上。
解决方案很简单 —— 在Maven pom 中添加 spring-tx:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.0.RELEASE</version>
</dependency>
当然,这不仅限于事务,如果缺少 AOP,也会抛出类似错误:
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException:
Unexpected exception parsing XML document from class path resource [/WEB-INF/mvc-servlet.xml];
nested exception is java.lang.NoClassDefFoundError:
org/aopalliance/aop/Advice
现在所需的 JAR 包是:spring-aop:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.0.RELEASE</version>
</dependency>
6. 总结
在本文结束时,我们应该对导致 Bean Definition Store Exception 的各种原因和问题有清晰的了解,并对如何解决这些问题有良好的把握。
部分异常示例的实现可以在 GitHub 项目 中找到——这是一个基于 Eclipse 的项目,导入和运行非常容易。