SpringCacheBasedUserCache 为空
Posted
技术标签:
【中文标题】SpringCacheBasedUserCache 为空【英文标题】:SpringCacheBasedUserCache is null 【发布时间】:2017-04-07 13:25:08 【问题描述】:我有使用 Spring Boot、Spring Security 和 Spring Data 的网络应用程序。它是无状态的。
我想避免总是为用户访问调用 db。所以我想使用 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);
...
我有一个实现 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 为空
【问题讨论】:
您的UserServiceImpl
不是 Spring 管理的 bean,因此不会注入任何内容。旁边你的代码有缺陷。您放入缓存中的user
将始终为null
。
不要自己缓存,只需将自己的 UserDetailsService
包装在 CachingUserDetailsService
中,这将为您完成繁重的工作。
【参考方案1】:
要么将@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
,因此无需再次使用。只需将缓存注入配置类并构造一个CachingUserDetailsService
,它代表您的UserDetailsService
来检索用户。
当然,您必须从自己的UserDetailsService
中删除缓存,现在可以专注于用户管理/检索,而不是与缓存混合。
Edit(1): 构造函数不是公开的,这使得创建 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。
【讨论】:
CachingUserDetailsService(UserDetailsService) 不公开 该死的错过了构造函数不是public
。奇怪的是 xml 很容易配置,但对于基于 java 的配置显然只能为jdbcAuthentication
配置(轻松)。您可以通过使用 BeanUtils
和 ClassUtils
创建实例来解决它。 (见修改后的答案)。
好的,如果用户修改了密码,我需要删除缓存用户吗?
那么你要么需要让你的 UserDetailsService
由 Spring 管理(正如在方法上放置 @Bean
注释所提到的那样)来获取缓存并自己进行失效等。或者您可以使用 spring ApplicationListener
和发布者使其事件驱动。\
@M.Deinum 当ClassUtils.getConstructorIfAvailable()
找不到构造函数时,我错过了什么吗?我看到 3.2.x 中有一个修复程序有望很快发布以上是关于SpringCacheBasedUserCache 为空的主要内容,如果未能解决你的问题,请参考以下文章