spring 中的依赖注入和序列化对象
Dependency injection and serialization Object in spring
我有一个配置了 spring 安全性的应用程序。
一切正常。
UserDetailService 是:
@Service(value = "userDetail")
public class UserDetailServiceImpl implements UserDetailsService, Serializable {
private static final long serialVersionUID = 3487495895819392L;
@Autowired
private IUserDetailRepository iUserDetailRepository;
@Autowired
private IUserRoleRepository iUserRoleRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = iUserDetailRepository.loadUserByUsername(username);
List<UserRole> roles = iUserRoleRepository.getAllRoleByUserName(username);
UserDetails u = new UserDetails() {
@Override
public boolean isEnabled() {
// return user.getEnable();
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public String getUsername() {
// return user.getUsername();
return "reyhane";
}
@Override
public String getPassword() {
// return user.getPassword();
return "reyhane";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ADMIN");
authorities.add(authority);
return authorities;
}
};
return u;
}
}
之后,我被迫通过此配置配置 spring 会话,以将 spring 安全上下文保存到 Redis 中。
UserDetailService 中存在问题。
UserDetailService 有两个自动装配的文件,如上所示:
@Autowired
private IUserDetailRepository iUserDetailRepository;
@Autowired
private IUserRoleRepository iUserRoleRepository;
这两个自动装配的字段用于从数据库中获取用户和用户的角色信息。
有趣的是,当我像这样评论这两个自动装配时:
//@Autowired
private IUserDetailRepository iUserDetailRepository;
//@Autowired
private IUserRoleRepository iUserRoleRepository;
并手动填写用户和用户的 role.Spring 会话也正常工作,但是当这两个 @Autowired
存在于 class 中时,会引发以下异常:
Caused by:
org.springframework.core.serializer.support.SerializationFailedException:
Failed to serialize object using DefaultSerializer; nested exception
is java.io.NotSerializableException:
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor
at
org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:68)
~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] at
org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:35)
~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] at
org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:90)
~[spring-data-redis-1.7.2.RELEASE.jar:na] ... 35 common frames omitted
Caused by: java.io.NotSerializableException:
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor
at
java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
~[na:1.8.0_111] at
java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
~[na:1.8.0_111]
大家知道是怎么回事吗?
我不明白发生了什么。
我不知道在 google
中有什么搜索键
我想知道 spring 会话和 spring 安全之间发生了什么以及如何解决它。
感谢您的帮助
我用这个解决方案解决了我的问题:
private static IUserDetailRepository userDetailRepository;
private static IUserRoleRepository userRoleRepository;
@Autowired
public void setUserDetailRepository(IUserDetailRepository userDetailRepository) {
UserDetailServiceImpl.userDetailRepository = userDetailRepository;
}
@Autowired
public void setUserRoleRepository(IUserRoleRepository userRoleRepository) {
UserDetailServiceImpl.userRoleRepository = userRoleRepository;
}
这实际上与那些依赖关系无关,这是因为您使用的是(非 static
)内部 class。您应该使用嵌入式 static
class 或简单地使用 Spring Security 中的常规 User
class。 (更多关于内部、(非)静态嵌入式 classes 的信息可在 this answer.
中找到
简而言之,由于您使用的是内部 classes,因此需要存在外部 class 的实例。现在,在序列化 UserDetails
时,它还会尝试序列化外部 class。
最简单的解决方案是重写您的代码并使用 Spring 提供的安全性 User
class(假设您使用的是 Spring 安全性 4.2,您可以使用 UserBuilder
).
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = iUserDetailRepository.loadUserByUsername(username);
List<UserRole> roles = iUserRoleRepository.getAllRoleByUserName(username);
return User.withUsername(user.getUsername())
.password(user.getPassword())
.disabled(!user.getEnable())
.roles(roles.stream().map(<convert-to-SimpleGrantedAuthority>).collect(Collectors.toList()))
.build();
}
如果您使用的是 Spring Security before 4.2,您可以简单地使用构造函数构造一个 User
对象。
return new User(user.getUsername(), user.getPassword(), user.getEnable(), true, true, true, <convert-roles-to-SimpleGrantedAuthoritu>);
当 return 是一个具体的 class 时,它不需要外部 class 的实例(因为它不是内部 class)并且它将不要尝试序列化它。它只会序列化 User
而不会序列化其他内容。
我有一个配置了 spring 安全性的应用程序。
一切正常。
UserDetailService 是:
@Service(value = "userDetail")
public class UserDetailServiceImpl implements UserDetailsService, Serializable {
private static final long serialVersionUID = 3487495895819392L;
@Autowired
private IUserDetailRepository iUserDetailRepository;
@Autowired
private IUserRoleRepository iUserRoleRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = iUserDetailRepository.loadUserByUsername(username);
List<UserRole> roles = iUserRoleRepository.getAllRoleByUserName(username);
UserDetails u = new UserDetails() {
@Override
public boolean isEnabled() {
// return user.getEnable();
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public String getUsername() {
// return user.getUsername();
return "reyhane";
}
@Override
public String getPassword() {
// return user.getPassword();
return "reyhane";
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ADMIN");
authorities.add(authority);
return authorities;
}
};
return u;
}
}
之后,我被迫通过此配置配置 spring 会话,以将 spring 安全上下文保存到 Redis 中。
UserDetailService 中存在问题。
UserDetailService 有两个自动装配的文件,如上所示:
@Autowired
private IUserDetailRepository iUserDetailRepository;
@Autowired
private IUserRoleRepository iUserRoleRepository;
这两个自动装配的字段用于从数据库中获取用户和用户的角色信息。
有趣的是,当我像这样评论这两个自动装配时:
//@Autowired
private IUserDetailRepository iUserDetailRepository;
//@Autowired
private IUserRoleRepository iUserRoleRepository;
并手动填写用户和用户的 role.Spring 会话也正常工作,但是当这两个 @Autowired
存在于 class 中时,会引发以下异常:
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: org.springframework.dao.support.PersistenceExceptionTranslationInterceptor at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:68) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:35) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE] at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:90) ~[spring-data-redis-1.7.2.RELEASE.jar:na] ... 35 common frames omitted Caused by: java.io.NotSerializableException: org.springframework.dao.support.PersistenceExceptionTranslationInterceptor at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) ~[na:1.8.0_111] at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[na:1.8.0_111]
大家知道是怎么回事吗?
我不明白发生了什么。
我不知道在 google
中有什么搜索键
我想知道 spring 会话和 spring 安全之间发生了什么以及如何解决它。
感谢您的帮助
我用这个解决方案解决了我的问题:
private static IUserDetailRepository userDetailRepository;
private static IUserRoleRepository userRoleRepository;
@Autowired
public void setUserDetailRepository(IUserDetailRepository userDetailRepository) {
UserDetailServiceImpl.userDetailRepository = userDetailRepository;
}
@Autowired
public void setUserRoleRepository(IUserRoleRepository userRoleRepository) {
UserDetailServiceImpl.userRoleRepository = userRoleRepository;
}
这实际上与那些依赖关系无关,这是因为您使用的是(非 static
)内部 class。您应该使用嵌入式 static
class 或简单地使用 Spring Security 中的常规 User
class。 (更多关于内部、(非)静态嵌入式 classes 的信息可在 this answer.
简而言之,由于您使用的是内部 classes,因此需要存在外部 class 的实例。现在,在序列化 UserDetails
时,它还会尝试序列化外部 class。
最简单的解决方案是重写您的代码并使用 Spring 提供的安全性 User
class(假设您使用的是 Spring 安全性 4.2,您可以使用 UserBuilder
).
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = iUserDetailRepository.loadUserByUsername(username);
List<UserRole> roles = iUserRoleRepository.getAllRoleByUserName(username);
return User.withUsername(user.getUsername())
.password(user.getPassword())
.disabled(!user.getEnable())
.roles(roles.stream().map(<convert-to-SimpleGrantedAuthority>).collect(Collectors.toList()))
.build();
}
如果您使用的是 Spring Security before 4.2,您可以简单地使用构造函数构造一个 User
对象。
return new User(user.getUsername(), user.getPassword(), user.getEnable(), true, true, true, <convert-roles-to-SimpleGrantedAuthoritu>);
当 return 是一个具体的 class 时,它不需要外部 class 的实例(因为它不是内部 class)并且它将不要尝试序列化它。它只会序列化 User
而不会序列化其他内容。