将类标记为 @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);
}
复制步骤:
- 登录
- 重新启动应用程序(不登录)
- 重新加载页面(仍应登录用户)
- 注销
- 尝试与同一用户再次登录。春季尝试对用户进行身份验证时会触发错误。
当其他人错误地定义自定义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中,以下代码完全不知道这些机制。