После маркировки класса как @Transactional
(см. Ниже), я получаю LinkageErrors о «попытке определить дубликат класса», когда мое приложение перезагружается, когда пользователь все еще вошел в систему.
Ошибка:
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 - это дао, которое мы используем в нашем пользовательском UserDetailsService для загрузки пользователей во время аутентификации.
Original 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
public HibernateTransactionManager transactionManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
Шаги для воспроизведения:
- Войти в систему
- Перезапустить приложение (без выхода из системы)
- Перезагрузить страницу (пользователь все еще должен войти в систему)
- Выйти
- Попытаться снова войти в систему с тем же пользователем.Ошибка запускается, когда Spring пытается аутентифицировать пользователя.
Я видел, как другие пользователи переполнения стека сталкивались с этой проблемой, когда они неправильно определяют собственный ClassLoader ( здесь );однако я не использую пользовательский ClassLoader.
Потенциально релевантные версии зависимостей:
- Java: 11
- Spring Boot: 2.1.1.RELEASE
- Пружина: 5.1.3.RELEASE
- Пружина Безопасность: 5.1.4.RELEASE