2013-03-05 190 views
0

这个问题证明解决起来非常棘手。平常的故事,继承了一个维护非常糟糕的Java Web应用程序,没有单元测试和各种古老的jar依赖项,没有版本信息转储到使用Ant构建的lib目录中。为了更好地维护和理解我迁移到Maven的依赖关系。随后,我意识到Spring的版本相当老旧(Spring 2.x和Spring Security 2.0.3)。我成功升级到Spring 2.5。我现在已经开始将Spring迁移到3.1.2.RELEASE,并将Spring Security升级到3.1.3.RELEASE。将Spring Security 2.5升级到3.1 - java.lang.NoClassDefFoundError:org/springframework/security/Authentication

一切都编译完成,我也没有得到任何命名空间问题(在Spring XML配置文件的头文件中声明),但是在作为WAR文件部署到Tomcat容器时失败。日志文件报告:

Could not instantiate bean class [com.mydomain.repository.ReportDaoImpl]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/security/Authentication 
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:997) 

我检查,并org.springframework.security.Authentication属于老春季安全罐子(2.0.4)

我目前的Maven依赖如下:

<spring.version>3.1.2.RELEASE</spring.version> 

     <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-webmvc</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-aop</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-context</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-context-support</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-core</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-tx</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework</groupId> 
     <artifactId>spring-jdbc</artifactId> 
     <version>${spring.version}</version> 
    </dependency> 

    <!-- SPRING SECURITY --> 

      <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-acl</artifactId> 
     <version>3.1.3.RELEASE</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-config</artifactId> 
     <version>3.1.3.RELEASE</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-core</artifactId> 
     <version>3.1.3.RELEASE</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-taglibs</artifactId> 
     <version>3.1.3.RELEASE</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-web</artifactId> 
     <version>3.1.3.RELEASE</version> 
    </dependency> 

    <dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-crypto</artifactId> 
     <version>3.1.3.RELEASE</version> 
    </dependency> 

我的security.xml最小:

<?xml version="1.0" encoding="UTF-8"?> 

<beans:beans xmlns="http://www.springframework.org/schema/security" 
    xmlns:beans="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.1.xsd 
     http://www.springframework.org/schema/security 
     http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 

<http auto-config='true'> 
    <intercept-url pattern="/**" access="ROLE_Admin" /> 
</http> 

<authentication-manager> 
    <authentication-provider> 
     <user-service> 
      <user name="admin" password="password" authorities="ROLE_Admin" /> 
     </user-service> 
    </authentication-provider> 
</authentication-manager>   

我所有的其他的Spring配置文件使用下面的命名空间标题在他们CONFIGS:

<?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:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation=" 
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 
     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/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> 

据我所知,这个应用程序包含关于春天没有注释。

那么Spring实例化一个DAO对象时,Spring Security 2.0.4类org.springframework.security.Authentication如何获得Spring 3.1类org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory的请求(它没有任何关系与春季安全设置)。可能是DAO被挑选出来,因为它是第一个bean,以便通过类加载器(通过Spring依赖注入容器)在applicationContext.xml中实例化,但是我看不到如何在此应用程序中存在某处引用一个老的2.0.4类。因为一切都编译好了,而且Maven pom只引用了3.1我的观点是必须有一些配置在某个地方仍然试图吸引一个老的类。任何具有Spring Security知识的人(特别是将大型应用程序从版本2升级到版本3)可能会遇到此问题,但我无法通过谷歌查找完全匹配。感谢您对此提出的任何建议。目前难住。

快速更新:

applicationContext.xml文件具有命名空间头球高出给出和DAO是简单地引用如下:

<bean id="reportDao" class="com.mydomain.repository.ReportDaoImpl"> 
    <property name="dataSource" ref="myDataSource" /> 
</bean> 

实在没有什么更给它。 ApplicationContext的拉动在另一个上下文中的applicationContext文件-数据源其中声明(相同的命名空间标题如上再次):

<bean id="parentDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
    destroy-method="close"> 
    <property name="driverClassName" value="${jdbc.driverClassName}" /> 
</bean> 

<bean id="myDataSource" parent="parentDataSource"> 
    <property name="url" value="${jdbc.url}" /> 
    <property name="username" value="${jdbc.username}" /> 
    <property name="password" value="${jdbc.password}" /> 
</bean> 

的ReportDao是写得不好的程序代码1500行。它是一个POJO并实现了rg.springframework.context.ApplicationContextAware。它还使用org.springframework.jdbc.core.support.JdbcDaoSupport对数据库执行CRUD操作。

运行MVN -X的依赖性输出(已切换到春天[主] 3.0.7):

org.springframework:spring-webmvc:jar:3.0.7.RELEASE:compile 
    org.springframework:spring-asm:jar:3.0.7.RELEASE:compile 
    org.springframework:spring-beans:jar:3.0.7.RELEASE:compile 
    org.springframework:spring-expression:jar:3.0.7.RELEASE:compile 
    org.springframework:spring-web:jar:3.0.7.RELEASE:compile 
org.springframework:spring-aop:jar:3.0.7.RELEASE:compile 
    aopalliance:aopalliance:jar:1.0:compile 
org.springframework:spring-context:jar:3.0.7.RELEASE:compile 
org.springframework:spring-context-support:jar:3.0.7.RELEASE:compile 
org.springframework:spring-core:jar:3.0.7.RELEASE:compile 
org.springframework:spring-tx:jar:3.0.7.RELEASE:compile 
org.springframework:spring-jdbc:jar:3.0.7.RELEASE:compile 
org.springframework.security:spring-security-acl:jar:3.1.3.RELEASE:compile 
org.springframework.security:spring-security-config:jar:3.1.3.RELEASE:compile 
org.springframework.security:spring-security-core:jar:3.1.3.RELEASE:compile 
org.springframework.security:spring-security-taglibs:jar:3.1.3.RELEASE:compile 
org.springframework.security:spring-security-web:jar:3.1.3.RELEASE:compile 
org.springframework.security:spring-security-crypto:jar:3.1.3.RELEASE:compile 

看起来不错,我相信。

的唯一弹簧罐子在WEB-INF/lib中交付WAR文件的目录(grepped为一定)为:

./spring-aop-3.0.7.RELEASE.jar 
./spring-asm-3.0.7.RELEASE.jar 
./spring-beans-3.0.7.RELEASE.jar 
./spring-context-3.0.7.RELEASE.jar 
./spring-context-support-3.0.7.RELEASE.jar 
./spring-core-3.0.7.RELEASE.jar 
./spring-expression-3.0.7.RELEASE.jar 
./spring-jdbc-3.0.7.RELEASE.jar 
./spring-security-acl-3.1.3.RELEASE.jar 
./spring-security-config-3.1.3.RELEASE.jar 
./spring-security-core-3.1.3.RELEASE.jar 
./spring-security-crypto-3.1.3.RELEASE.jar 
./spring-security-taglibs-3.1.3.RELEASE.jar 
./spring-security-web-3.1.3.RELEASE.jar 
./spring-tx-3.0.7.RELEASE.jar 
./spring-web-3.0.7.RELEASE.jar 
./spring-webmvc-3.0.7.RELEASE.jar 

同样,看起来合理的。

清除“身份验证”的源代码并没有帮助。这看起来像一个传递运行时依赖问题。它在编译时并未被注意到,也没有被声明为第一级依赖。但在运行时(在Tomcat 6容器中),在部署时会请求对旧库文件进行流氓引用。

要删除我的Tomcat实例并从头开始,以防万一。

+0

你可以发布'ReportDaoImpl'类吗?这似乎是这类自动装配中的一个问题。此外,你的自动装配在spring配置中如何触发? – benzonico 2013-03-05 13:50:13

+0

没有自动装配。这是老派的XML配置。已经把上面的相关部分作为更新。 applicationConfig被容器通过web.xml引入(正如我相信你熟悉的那样)。 – arcseldon 2013-03-05 14:12:37

+0

我会仔细检查你的classpaths(编译和运行时),因为maven poms很少是你最终定义的定义语句。运行“mvn -X”并检查列出的所有罐子,以确保不会针对2.0.x罐子进行编译。另外grep你的java源代码为“Authentication”和“org.springframework.security”,并检查任何使用Spring Security类的代码中的包是否正确。 – 2013-03-05 14:33:11

回答

2

好的,终于解决了这个问题。 NoClassDefFoundError正是它在锡上所说的。正如卢克泰勒所问:“你确定你重新编译了吗?”那么,是的,不。我绝对重新编译,清理目标(使用Maven)等。而且第一次使用反编译器查看生成的类“XXXDao”的源代码时,我看到了我的更改。但我也注意到,当我从java源码添加/删除了几行时,堆栈跟踪中的错误仍保留在同一行(随机)行号上。这解释了我以某种方式得到了一个陈旧的.class文件。事实证明,Maven和/或Eclipse(m2eclipse插件)以某种方式设法将类文件编译到我的核心项目(不是目标)的WEB-INF/classes目录中,并且非确定性地覆盖目标中的WEB-INF/classes目录一些类。更奇怪的是,它总是在将类压缩成.WAR时部署旧类。所以你有一个看起来正确的爆炸内容的情况,但实际上是压缩了不同类的WAR文件。获得的经验 - 如果你得到这种行为,仔细检查编译步骤,并试着找出旧的类文件(引用旧的认证类)是如何进入你的新版本的。感谢那些对这篇文章作出贡献的人!