当前位置: 首页 > 知识库问答 >
问题:

SpringCacheBasedUserCache为空

易刚捷
2023-03-14

我有使用spring boot、spring security和spring data的web应用程序。它是无国籍的。

我想避免总是调用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);
    }
    ...
}

我有一个类谁实现用户细节和另一个谁实现用户细节服务

@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为空

共有1个答案

翟鹏
2023-03-14

要么将@Bean放在userDemailsServiceBean方法上,要么(如建议的那样)完全从UserDemailsService中删除缓存,并将其包装在CachingUserDemailsService中,而不是简单地覆盖userDemailsService方法。

@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;
    }
    ...
}

您的其他配置上已经有@EnableCache,因此无需再次拥有它。只需将缓存注入配置类并构造一个CachingUserDemailsService,它委托给您的UserDemailsService来检索用户。

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

Edit(1):构造函数不是公共的,这使得创建bean更加困难。这可以通过使用< code>BeanUtils和< code>ClassUtils来实现。用下面的代码替换对< code>new的调用应该会创建一个实例。

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

编辑(2):显然,我已经遇到过一次(大约2年前),并为其注册了此问题。

 类似资料:
  • 问题内容: 我有Ubuntu 10.10和apache2,php 5.3.3-1和mysql 5.1。 我正在通过URL向页面传递一些值。在该页面上,如果我这样做了,那么我会看到数组的内容。但是,如果我这样做数组是空的。任何想法为什么会这样? 问题答案: 也可以尝试检查php.ini中的“ request_order” 选项:

  • 我的问题是无法使用和获取文本字段。我尝试使用XPath来选择对象,但没有成功。 这是我的代码: 我重新提出这个问题是因为旧的问题有点让人困惑,我想。这是旧的 XML形式的我的文档(Document.getXML()) 我需要选择文本字段,做一个邮件合并,我的计划将是复制和移动字段。如果有更好的方法,我愿意尝试一下:)

  • 正如您将看到的,当涉及到Java和JavaFX时,我是一个大傻瓜。我花了很多时间四处阅读(各种论坛帖子和tuts)并试图弄清楚我自己是从哪里得到这个问题的,但它已经到了我发帖从一个了解他们的业务的人那里得到反馈的地步。 在回复的时候,请你花点时间解释一下为什么有些东西不能工作,以及一些一般性的指示?这里是我到目前为止所拥有的(我的FXML和我的两个类)任何指针都将是美妙的!! 我的FXML; 现在

  • 问题内容: 在Java代码中执行空检查时,如果您为空值抛出IllegalArgumentExceptions,那么您将使用哪种消息模板? 我们倾向于使用这样的东西 哪个更好:“ is null”或“ was null”,为什么? 对我来说,“是空的”感觉更自然。 问题答案: 由于由于失败的前提条件检查而引发,因此,我认为除了陈述事实以外,还应说明已违反的 要求 。 就是说,而不是说。 关于使用库进

  • 问题内容: 无法使用XMLHttpRequest获取数据(状态0,responseText为空): 它警告“状态0”。 与localhost请求的情况相同(cd_catalog.xml保存为本地文件) 但是使用本地主机IP请求 并与本地文件请求 一切正常(状态200) 什么会导致在线请求出现问题(状态= 0)? PS:Live HTTP标头显示在所有4种情况下一切正常: PS2:VMWare上的A

  • 我有以下测试WebAPI代码,我没有在生产中使用WebAPI,但我之所以这样做是因为我讨论了这个问题:WebAPI异步问题 不管怎样,下面是冒犯的WebAPI方法: 因此,我认为第二个异常是预期的,因为当完成时,它很可能位于另一个线程上,其中作为线程静态变量将不再解析为适当的值。现在,基于同步上下文,它实际上可以在await之后被强制返回到相同的线程,但我在测试中没有做任何花哨的事情。这只是对的简