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 的项目,导入和运行非常容易。