Spring force @Cacheable to use putifAbsent instead of put

江枫思渺然 提交于 2021-02-08 10:01:44

问题


I've Spring cache implemented as below

@Component
public class KPCacheExample {

    private static final Logger LOG = LoggerFactory.getLogger(KPCacheExample.class);

    @CachePut(value="kpCache")
    public String saveCache(String userName, String password){
        LOG.info("Called saveCache");
        return userName;
    }

    @Cacheable(value="kpCache")
    public String getCache(String userName, String password){
        LOG.info("Called getCache");
        return "kp";
    }

}

And Java Config file

@Configuration
@ComponentScan(basePackages={"com.kp"})
public class GuavaCacheConfiguration {


    @Bean
    public CacheManager cacheManager() {
     GuavaCacheManager guavaCacheManager =  new GuavaCacheManager("kpCache");
     guavaCacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterAccess(2000, TimeUnit.MILLISECONDS).removalListener(new KPRemovalListener()));
     return guavaCacheManager;
    }

}

By default the spring uses put method in the cache interface to update/put values in the cache. How can I force the spring to use putifabsent method to be invoked, such that I can get null value if cache is missed or in other wards first request to the method with unique username and password should return null and subsequent request to that username and password should return username.


回答1:


Well, looking through Spring's Cache Abstraction source, there does not appear to be a configuration setting (switch) to default the @CachePut to use the "atomic" putIfAbsent operation.

You might be able to simulate the "putIfAbsent" using the unless (or condition) attribute(s) of the @CachePut annotation, something like (based on the Guava impl)...

@CachePut(value="Users", key="#user.name" unless="#root.caches[0].getIfPresent(#user.name) != null")
public User save(User user){
    return userRepo.save(user);
}

Also note, I did not test this expression, and it would not be "atomic" or portable using a different Cache impl. The expression ("#root.caches[0].get(#user.name) != null") maybe more portable.

Giving up the "atomic" property may not be desirable so you could also extend the (Guava)CacheManager to return a "custom" Cache (based on GuavaCache) that overrides the put operation to delegate to "putIfAbsent" instead...

class CustomGuavaCache extends GuavaCache {

    CustomGuavaCache(String name, com.google.common.cache.Cache<Object, Object> cache, boolean allowNullValues) {
        super(name, cache, allowNullValues);
    }

    @Override
    public void put(Object key, Object value) {
        putIfAbsent(key, value);
    }
}

See the GuavaCache class for more details.

Then...

class CustomGuavaCacheManager extends GuavaCacheManager {

    @Override
    protected Cache createGuavaCache(String name) {
        return new CustomGuavaCache(name, createNativeGuavaCache(name), isAllowNullValues());
    }
}

See GuavaCacheManager for further details, and specifically, have a look at line 93 and createGuavaCache(String name).

Hope this helps, or at least gives you some more ideas.



来源:https://stackoverflow.com/questions/29343980/spring-force-cacheable-to-use-putifabsent-instead-of-put

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!