【SpringMVC】Unable to locate Spring NamespaceHandler for XML schema产生的原因及解决方法

转自:https://blog.csdn.net/shuimuniao/article/details/80805308

结论

原因有两个:

  • context、aop及其他spring相关的xml命名空间需要特殊Jar包才能解析。必须确保pom文件中依赖了对应的spring jar包。context对应spring-context.jar包。aop对应spring-aop.jar包。
  • 如果配置文件中定义了2个及以上的spring xml命名空间,那么要防止jar包中配置文件相互覆盖。spring系列jar包中配置文件的命名及路径完全相同,默认情况下这些配置文件会相互覆盖。使用maven-shade-plugin来修改同名配置文件的处理方法,将覆盖改为合并。

场景还原

这是一个maven项目,项目框架采用的是Spring。项目的结构如下所示。

+- performance
   +- pom.xml //maven配置文件
   +- target  //编译生成文件
   |  +- performance-1.0.0-SNAPSHOT.jar //可运行的jar文件
   |  +- original-performance-1.0.0-SNAPSHOT.jar
   |  \- classes //编译项目源文件生成class文件
   +- src     //源码文件
      +- test
     +- main
         +- java
         |  \- concert
         |     +- Audience.java
         |     +- Main.java
         |     +- Performance.java
         |     \- PerformanceImpl.java
         +- resources
            \- performance.xml
  • 在项目根目录performance中执行命令mvn clean package就可以生成可执行的jar文件performance-1.0.0-SNAPSHOT.jar
  • 生成jar文件后,执行命令jar -jar target/performance-1.0.0-SNAPSHOT.jar就可以运行jar文件。
    Spring配置文件
  • xml文件中定义了两个命名空间context及aop。
  • context命名空间用于设定自动扫描包名,用于发现bean。
  • aop用于配置aspectJ注解的解析。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="concert" />
    <aop:aspectj-autoproxy />
    <bean class="concert.Audience" />
    <!--<bean class="concert.PerformanceImpl" />-->
</beans>

pom配置文件

  • aop命名空间需要org.springframework:spring-aop:4.3.14.RELEASE解析。
  • context命名空间需要org.springframework:spring-context:4.3.14.RELEASE解析。
<!-- ... -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.14.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.14.RELEASE</version>
    </dependency>
    <!-- ... -->
    </dependencies>
<!-- ... -->

程序入口源码文件

public class Main {
    public static void main(String[] args) {
       ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("performance.xml");
       Performance p = context.getBean(Performance.class);
       p.perform();
       context.close();
    }
}

生成可运行的jar文件

mvn clean package
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.059 s
[INFO] Finished at: 2018-06-25T16:04:51+08:00
[INFO] ------------------------------------------------------------------------

运行jar文件

java -jar target/performance-1.0.0-SNAPSHOT.jar
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
Offending resource: class path resource [performance.xml]
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:70)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:118)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:110)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:301)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1407)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1400)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:172)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:142)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:94)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:508)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:392)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:252)
	at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
	at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
	at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:614)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:515)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
	at concert.Main.main(Main.java:7)

问题分析方法

  • 百度问题Unable to locate Spring NamespaceHandler for XML schem原因。
    有一种解释说,context及aop都属于自定义命名空间。这些命名空间的规范描述需要特殊的方法来解析。context规范描述需要spring-context来解析,aop规范描述需要spring-aop来解析。如果没有将解析代码spring-context和spring-aop打包进最终生成的performance-1.0.0-SNAPSHOT.jar文件,那么运行时就会出现这个问题。
  • 检查是否将spring-context及spring-aop添加到依赖列表。
  • 检查是否正确书写了context及aop的规范描述URL。

对比正常运行项目

正常项目 错误项目
pom配置文件 依赖spring-context及spring-aop 依赖spring-context及spring-aop
spring配置文件 只引用了一个自定义命名空间aop 引用了两个命名空间,aop和context

取消使用context命名空间。context命名空间用于设定自动扫描目录,自动识别bean对象。可以通过显式声命bean来取消context命名空间。即使用声明bean文件。

重新运行mvn clean package生成jar文件,执行jar文件,可以正常运行,不再抛出异常

初步结论:spring配置文件不能定义2个及2个以上的命名空间。

自定义classPath运行concert.Main

还原context命名空间,使用IntelliJ运行concert.Main,竟然正常运行!

IntelliJ本质是自定义classPath运行程序的。在terminal中自定义classpath运行程序,是可以正确运行程序的,并未抛出BeanDefinitionParsingException异常。详情如下所示。

around--before
Silencing cell phones
Taking seats
performanceImpl perform...
around--after
CLAP CLAP CLAP!!!

推翻之前结论:“spring配置文件不能定义2个及2个以上的命名空间“

google无法解析Spring命名空间问题

  • 一种解释是,spring-context及spring-aop中有同名的配置文件,这些文件在最后打包进performance-1.0.0-SNAPSHOT.jar时,会出现覆盖问题。因此,就会有一个模块(aop或者context)无法正常发挥作用。

解决方法

在maven-shade-plugin插件中通过Resource Transformers将所有的spring.schemas文件中的内容都合并到一起。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>1.2.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <!-- 不覆盖同名文件,而是追加合并同名文件 -->
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.schemas</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.tooling</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>concert.Main</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

重新打包运行,可以正常运行。

猜你喜欢

转载自blog.csdn.net/shaotaiban1097/article/details/91139027
今日推荐