SpringCacheBasedUserCache 为空
SpringCacheBasedUserCache is null
我有使用 spring 引导、spring 安全和 spring 数据的 Web 应用程序。它是无状态的。
我想避免总是为用户访问调用数据库。所以我想使用 SpringCacheBasedUserCache。
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("city"), new ConcurrentMapCache("userCache")));
return cacheManager;
}
@Bean
public UserCache userCache() throws Exception {
Cache cache = (Cache) cacheManager().getCache("userCache");
return new SpringCacheBasedUserCache(cache);
}
}
@EnableCaching
@Configuration
@EnableWebSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return new UserServiceImpl(commerceReposiotry, repository, defaultConfigRepository);
}
...
}
我有一个 class 实现了 UserDetails,另一个实现了 UserDetailsService
@Service
public class UserServiceImpl implements UserDetailsService, UserService {
private final CommerceRepository commerceReposiotry;
private final UserAppRepository repository;
private final DefaultConfigRepository defaultConfigRepository;
@Autowired
private UserCache userCache;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
public UserServiceImpl(final CommerceRepository commerceReposiotry, final UserAppRepository repository, final DefaultConfigRepository defaultConfigRepository) {
this.commerceReposiotry = commerceReposiotry;
this.repository = repository;
this.defaultConfigRepository = defaultConfigRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = userCache.getUserFromCache(username);
UserApp userapp = null;
if (user == null) {
userapp = repository.findByUsername(username);
}
if (userapp == null) {
throw new UsernameNotFoundException("Username " + username + " not found");
}
userCache.putUserInCache(user);
return new CustomUserDetails(userapp);
}
...
}
在loadUserByUsername方法中,userCache为空
要么将 @Bean
放在 userDetailsServiceBean
方法上,要么(按照建议)从 UserDetailsService
中完全删除缓存并将其包装在 CachingUserDetailsService
中,而只是覆盖userDetailsService
方法代替。
@Configuration
@EnableWebSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private UserCache userCache;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public UserDetailsService userDetailsService() throws Exception {
UserServiceImpl userService = new UserServiceImpl(commerceReposiotry, repository, defaultConfigRepository);
CachingUserDetailsService cachingUserService = new CachingUserDetailsService(userService);
cachingUserService.setUserCache(this.userCache);
return cachingUserService;
}
...
}
您的其他配置上已经有 @EnableCaching
,因此无需再次进行。只需将缓存注入配置 class 并构造一个 CachingUserDetailsService
委托给您的 UserDetailsService
来检索用户。
当然,您必须从自己的 UserDetailsService
中删除缓存,现在可以专注于用户 management/retrieval,而不是与缓存混合。
Edit(1): 构造函数没有 public 使创建 bean 变得更加困难。这可以使用 BeanUtils
和 ClassUtils
来实现。用以下内容替换对 new
的调用应该创建一个实例。
private UserDetailsService cachingUserDetailsService(UserDetailsService delegate) {
Constructor<CachingUserDetailsService> ctor = ClassUtils.getConstructorIfAvailable(CachingUserDetailsService.class, UserDetailsService.class);
return BeanUtils.instantiateClass(ctor, delegate);
}
编辑 (2): 显然我已经遇到过一次(大约 2 年前)并为此注册了 this issue。
我有使用 spring 引导、spring 安全和 spring 数据的 Web 应用程序。它是无状态的。
我想避免总是为用户访问调用数据库。所以我想使用 SpringCacheBasedUserCache。
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("city"), new ConcurrentMapCache("userCache")));
return cacheManager;
}
@Bean
public UserCache userCache() throws Exception {
Cache cache = (Cache) cacheManager().getCache("userCache");
return new SpringCacheBasedUserCache(cache);
}
}
@EnableCaching
@Configuration
@EnableWebSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return new UserServiceImpl(commerceReposiotry, repository, defaultConfigRepository);
}
...
}
我有一个 class 实现了 UserDetails,另一个实现了 UserDetailsService
@Service
public class UserServiceImpl implements UserDetailsService, UserService {
private final CommerceRepository commerceReposiotry;
private final UserAppRepository repository;
private final DefaultConfigRepository defaultConfigRepository;
@Autowired
private UserCache userCache;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
public UserServiceImpl(final CommerceRepository commerceReposiotry, final UserAppRepository repository, final DefaultConfigRepository defaultConfigRepository) {
this.commerceReposiotry = commerceReposiotry;
this.repository = repository;
this.defaultConfigRepository = defaultConfigRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = userCache.getUserFromCache(username);
UserApp userapp = null;
if (user == null) {
userapp = repository.findByUsername(username);
}
if (userapp == null) {
throw new UsernameNotFoundException("Username " + username + " not found");
}
userCache.putUserInCache(user);
return new CustomUserDetails(userapp);
}
...
}
在loadUserByUsername方法中,userCache为空
要么将 @Bean
放在 userDetailsServiceBean
方法上,要么(按照建议)从 UserDetailsService
中完全删除缓存并将其包装在 CachingUserDetailsService
中,而只是覆盖userDetailsService
方法代替。
@Configuration
@EnableWebSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private UserCache userCache;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public UserDetailsService userDetailsService() throws Exception {
UserServiceImpl userService = new UserServiceImpl(commerceReposiotry, repository, defaultConfigRepository);
CachingUserDetailsService cachingUserService = new CachingUserDetailsService(userService);
cachingUserService.setUserCache(this.userCache);
return cachingUserService;
}
...
}
您的其他配置上已经有 @EnableCaching
,因此无需再次进行。只需将缓存注入配置 class 并构造一个 CachingUserDetailsService
委托给您的 UserDetailsService
来检索用户。
当然,您必须从自己的 UserDetailsService
中删除缓存,现在可以专注于用户 management/retrieval,而不是与缓存混合。
Edit(1): 构造函数没有 public 使创建 bean 变得更加困难。这可以使用 BeanUtils
和 ClassUtils
来实现。用以下内容替换对 new
的调用应该创建一个实例。
private UserDetailsService cachingUserDetailsService(UserDetailsService delegate) {
Constructor<CachingUserDetailsService> ctor = ClassUtils.getConstructorIfAvailable(CachingUserDetailsService.class, UserDetailsService.class);
return BeanUtils.instantiateClass(ctor, delegate);
}
编辑 (2): 显然我已经遇到过一次(大约 2 年前)并为此注册了 this issue。