结论
原因有两个:
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: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解析。
程序入口源码文件
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.
at org.springframework.context.support.ClassPathXmlApplicationContext.
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命名空间。即使用
重新运行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文件中的内容都合并到一起。
重新打包运行,可以正常运行。
————————————————
版权声明:本文为CSDN博主「shuimuniao」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shuimuniao/article/details/80805308