将类标记为@Transactional后"LinkageError--> loader 'app' attempted duplicate class definition"



将类标记为 @Transactional(见下文),当我的应用程序重新加载时,我将在用户仍在登录时获得有关"未遂重复类定义"的链接。

错误:

org.springframework.security.authentication.InternalAuthenticationServiceException: java.lang.LinkageError-->loader 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) attempted duplicate class definition for [redacted].AdminUserDao$$FastClassBySpringCGLIB$$2ffa020e.
        at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:126)

当adminuserdao是我们在身份验证期间加载用户加载用户的dao。

原始adminuserdao.java

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class AdminUserDao {
    private final SessionFactory sessionFactory;
    @Autowired
    public AdminUserDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    public AdminUser getUserByEmailAddress(String emailAddress) {
        String hql = "from " + AdminUser.class.getName()
                + " admin_user where admin_user.emailAddress = :emailAddress";
        Session session = null;
        try {
          session = sessionFactory.openSession();
          return session
                .createQuery(hql, AdminUser.class)
                .setParameter("emailAddress", emailAddress)
                .uniqueResult();
       } finally {
          if (session != null && session.isOpen()) {
            session.close();
          }
    }
}

交易adminuserdao.java

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Transactional
@Repository
public class AdminUserDao {
    private final SessionFactory sessionFactory;
    @Autowired
    public AdminUserDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    public AdminUser getUserByEmailAddress(String emailAddress) {
        String hql = "from " + AdminUser.class.getName()
                + " admin_user where admin_user.emailAddress = :emailAddress";
        return sessionFactory.getCurrentSession()
                .createQuery(hql, AdminUser.class)
                .setParameter("emailAddress", emailAddress)
                .uniqueResult();
    }
}

事务管理器bean

@Bean
public HibernateTransactionManager transactionManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
    return new HibernateTransactionManager(sessionFactory);
}

复制步骤:

  1. 登录
  2. 重新启动应用程序(不登录)
  3. 重新加载页面(仍应登录用户)
  4. 注销
  5. 尝试与同一用户再次登录。春季尝试对用户进行身份验证时会触发错误。

当其他人错误地定义自定义classloader时,我在堆栈溢出中遇到了这个问题(此处);但是,我不使用自定义classloader。

潜在的相关依赖性版本:

  • Java:11
  • 春季靴子:2.1.1.Release
  • 春季:5.1.3.Release
  • 春季安全:5.1.4.Release

上面给出的链接:https://docs.spring.io/spring/docs/3.0.0.0.m3/reference/html/ch08s06.html由https://stackoverflow.com/users/1567452/jwilner给出正确的提示(thx;))

@transactional注释意味着Spring正在为您生成一个代理类,该类将您的方法包裹在以下内容:

GeneratedProxy {
void proxiedMethod(){
   try{ 
     tx.begin();
     yourClass.yourMethod(); 
     tx.commit();
   }
   .. plus usual rollback and error stuff .. 
}
}

现在春季有两个选项(请参阅https://botproxy.net/docs/how-to/mismatched-proxy-types-jdk-vs-vs-cglib-when-when-when-shen-shen-rish-enablecaching-with-custom-aop-aop-ap-ap-aop-ap-ap-aop-apvice/):

如果您的代码实现接口,他将使用JDK代理并公开接口的所有方法:

(请参阅例如https://www.byteslounge.com/tutorials/jdk-dynamic-proxies,https for JDK代理示例)

如果您的代码未实现任何接口,他将创建CGLIB代理(并且本质上猜测哪种方法暴露了)

最后,在他生成CGLIB代理的情况下,他将创建一个运行时类,例如authcuserservice $$ EnhancerBysBysPringCglib $$ 5C9DCB68

JDK代理,他将创建一个类似com.sun.proxy的类。$ proxy1631

这两个将被施放到设置器(生成的设置器)方法中的正确类:

在第一种情况下,您可以在父类中使用类本身在第二种情况下,您将使用该界面,否则您会得到org.springframework.beans.factory.beannotofrequiredtypeexception

在您的情况下,您也许可以摆脱 @transactional,就我的情况而

得出结论在Java 13中发生,可能是由于有关JEE和反射的变化,实际上在JDK1.8中,以下代码完全不知道这些机制。

最新更新