SpringCacheBasedUserCache 为空 [英] SpringCacheBasedUserCache is null

查看:32
本文介绍了SpringCacheBasedUserCache 为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有使用 spring boot、spring security 和 spring 数据的 web 应用程序.它是无状态的.

I have web applicatoin who use spring boot, spring security and spring data. it is stateless.

我想避免总是为用户访问而调用 db.所以我想使用 SpringCacheBasedUserCache.

I would like to avoid to alway call db for user acess. So i thinking using 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 的类和另一个实现 UserDetailsS​​ervice 的类

I have a class who implements UserDetails and another who implements 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 为空

In loadUserByUsername method, userCache is null

推荐答案

要么将 @Bean 放在 userDetailsS​​erviceBean 方法上,要么(按照建议)从 中删除缓存>UserDetailsS​​ervice 完全并将其包装在 CachingUserDetailsS​​ervice 中,而只需覆盖 userDetailsS​​ervice 方法.

Either put @Bean on the userDetailsServiceBean method or (as suggested) remove caching from your UserDetailsService completely and wrap it in a CachingUserDetailsService and instead simply override the userDetailsService method instead.

@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,因此无需再次使用.只需将缓存注入配置类并构造一个 CachingUserDetailsS​​ervice 委托给您的 UserDetailsS​​ervice 来检索用户.

You already have @EnableCaching on your other configuration so no need to have that again. Simply inject the cache into the configuration class and construct a CachingUserDetailsService which delegates to your UserDetailsService to retrieve the user.

当然,您必须从您自己的 UserDetailsS​​ervice 中删除缓存,它现在可以专注于用户管理/检索,而不是与缓存混合.

Ofcourse you will have to remove the caching from your own UserDetailsService which can now be focused on user management/retrieval instead of being mixed with caching.

Edit(1): 构造函数不是公开的,这使得创建 bean 变得更加困难.这可以使用 BeanUtilsClassUtils 来实现.用以下代码替换对 new 的调用应该会创建一个实例.

Edit(1): The constructor isn't public making it harder to create a bean. This can be achieved using BeanUtils and ClassUtils. Replace the call to new with the following should create an instance.

private UserDetailsService cachingUserDetailsService(UserDetailsService delegate) {
    Constructor<CachingUserDetailsService> ctor = ClassUtils.getConstructorIfAvailable(CachingUserDetailsService.class, UserDetailsService.class);
    return BeanUtils.instantiateClass(ctor, delegate);
}

编辑 (2): 显然我已经遇到过一次(大约 2 年前)并注册了 这个问题.

Edit (2): Apparently I already encountered this once already (about 2 years ago) and registered this issue for it.

这篇关于SpringCacheBasedUserCache 为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆