java - 将 Spring Security 2.5 升级到 3.1 - java.lang.NoClassDefFoundError : org/springframework/security/Authentication

标签 java spring-security migration noclassdeffounderror

事实证明,这个问题很难解决。通常的故事,继承了一个维护得很差的 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 XML 配置的 header 中声明),但在作为 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 属于旧的 Spring Security jar (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 配置文件在其配置中使用以下命名空间 header :

<?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 请求(这与 Spring 安全设置)。选择 DAO 可能是因为它是第一个 bean,以便由类加载器(通过 Spring 依赖注入(inject)容器)在 applicationContext.xml 中实例化,但我看不出如何在该应用程序中的某个地方仍然潜伏着一个引用一个旧的 2.0.4 类。由于一切都编译正常,并且 Maven pom 仅引用 3.1,我的看法是,一定有一些配置仍在尝试引入旧类。任何具有 Spring Security 知识的人(特别是将大型应用程序从版本 2 升级到版本 3)之前可能遇到过这个问题,但我无法通过谷歌找到完全匹配的问题。感谢您对此的任何建议。目前陷入困境。

快速更新:

applicationContext.xml 具有上面给出的命名空间 header ,并且 DAO 的引用如下:

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

真的没有什么更多的了。 applicationContext 拉入另一个上下文文件 applicationContext-datasource ,该文件声明(与上面相同的命名空间 header ):

 <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 依赖项的输出(已切换到 Spring [main] 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

我相信看起来不错。

可交付的 WAR 文件的 WEB-INF/lib 目录中唯一的 spring jar(经过 grep 确认)是:

./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 实例并从头开始。

最佳答案

好的,终于解决了这个特殊问题。 NoClassDefFoundError 正是它上面所说的那样。正如卢克·泰勒(Luke Taylor)问的那样:“你绝对确定你重新编译了吗?”嗯,是的,也不是。我确实重新编译、清理了目标(使用 Maven)等。当我第一次使用反编译器查看生成的类“XXXDao”的源代码时,我看到了我的更改。但我也注意到,当我从 java 源代码中添加/删除几行时,堆栈跟踪中的错误仍保留在同一(随机)行号上。这解释了我以某种方式得到了一个过时的 .class 文件。事实证明,Maven 和/或 Eclipse(m2eclipse 插件)以某种方式设法将类文件编译到我的核心项目(不是目标)的 WEB-INF/classes 目录中,并且不确定地覆盖目标中的 WEB-INF/classes 目录一些类(class)。更奇怪的是,在将类压缩到 .WAR 中时,它总是部署旧的类。因此,您会遇到分解内容看起来正确但实际上是具有不同类的压缩 WAR 文件的情况。

经验教训 - 如果您遇到这种行为,请仔细检查编译步骤,并尝试找出旧的类文件(引用旧的 Authentication 类)如何进入您的新构建。感谢那些对这篇文章做出贡献的人的指点!

关于java - 将 Spring Security 2.5 升级到 3.1 - java.lang.NoClassDefFoundError : org/springframework/security/Authentication,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15225385/

相关文章:

migration - Liquibase - 忽略旧的变更集

git cvsimport 失败 : Could not merge master into the current branch

asp.net - 有关将 .NET Windows 窗体应用程序迁移到 Web 应用程序的指南

java - 如何在Jmock中模拟对象?如果使用 new 运算符创建对象

java - 从 jaas LoginModule 访问 spring 上下文

java - 如何为 Spring Data 中的类配置 MongoDb 集合名称

java - 如何通过登录注销用户(非当前)?

java - spring-oauth RandomValueProviderTokenServices 类的实现技巧

java - 为什么 Spring 对待构造函数注入(inject)与 setter/field 注入(inject)不同?

java - build() 方法的工作和使用。请解释或分享一些链接