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

结论
原因有两个:
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注解的解析。

    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">
 
   
 
   
 
   
 
   

 
pom配置文件
aop命名空间需要org.springframework:spring-aop:4.3.14.RELEASE解析。
context命名空间需要org.springframework:spring-context:4.3.14.RELEASE解析。


   
        org.springframework
        spring-aop
        4.3.14.RELEASE
   

 
   
        org.springframework
        spring-context
        4.3.14.RELEASE
   

 
   
   


程序入口源码文件
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.(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.(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文件中的内容都合并到一起。

    org.apache.maven.plugins
    maven-shade-plugin
    1.2.1
   
       
            package
           
                shade
           

           
               
                   
                   
                        META-INF/spring.handlers
                   

                   
                        META-INF/spring.schemas
                   

                   
                        META-INF/spring.tooling
                   

                   
                        concert.Main
                   

               

           

       

   


重新打包运行,可以正常运行。
————————————————
版权声明:本文为CSDN博主「shuimuniao」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shuimuniao/article/details/80805308

你可能感兴趣的:(java)