Spring 3.1 @Cacheable - 方法仍然执行

作者:编程家 分类: spring 时间:2025-06-20

使用Spring框架的@Cacheable注解可以实现方法级别的缓存功能。这意味着当一个被@Cacheable注解修饰的方法被调用时,Spring会首先检查缓存中是否已经存在该方法的结果,如果存在,则直接返回缓存的结果,而不会执行该方法。然而,在某些情况下,即使方法被@Cacheable注解修饰,仍然会执行该方法并计算结果。本文将探讨这个问题,并提供解决方案。

一个常见的场景是,当使用@Cacheable注解修饰的方法中存在多个参数时,Spring默认会将这些参数序列化为一个缓存键,并将结果缓存起来。然而,对于某些复杂对象,其默认的序列化方式可能无法正确处理,导致无法正确生成缓存键。这时,即使方法被@Cacheable注解修饰,仍然会执行该方法并计算结果。

为了解决这个问题,可以使用自定义的缓存键生成器。通过实现org.springframework.cache.interceptor.KeyGenerator接口,可以自定义生成缓存键的逻辑。在自定义的缓存键生成器中,可以根据方法的参数来生成一个唯一的缓存键。这样,即使参数无法正确序列化,仍然可以生成正确的缓存键,并从缓存中获取结果。

下面是一个简单的示例代码,演示了如何使用自定义的缓存键生成器解决方法仍然执行的问题:

java

import org.springframework.cache.annotation.Cacheable;

import org.springframework.cache.interceptor.KeyGenerator;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class CacheConfig {

@Bean

public KeyGenerator customKeyGenerator() {

return (target, method, params) -> {

StringBuilder sb = new StringBuilder();

sb.append(target.getClass().getSimpleName());

sb.append(":");

sb.append(method.getName());

for (Object param : params) {

sb.append(":");

sb.append(param.toString());

}

return sb.toString();

};

}

}

public class UserService {

@Cacheable(cacheNames = "users", keyGenerator = "customKeyGenerator")

public User getUser(String username, String password) {

// 这里是获取用户的逻辑,假设需要耗费一定时间

return userRepository.findUserByUsernameAndPassword(username, password);

}

}

上述代码中,我们通过@Configuration注解将自定义的缓存键生成器注册为一个Spring Bean,并在@Cacheable注解中指定使用该生成器生成缓存键。在自定义的缓存键生成器中,我们将目标类的简单类名、方法名以及方法的参数拼接起来作为缓存键。这样,即使参数无法正确序列化,仍然可以生成正确的缓存键,并从缓存中获取结果。

解决方法仍然执行的问题

通过使用自定义的缓存键生成器,我们可以解决方法仍然执行的问题。自定义的缓存键生成器可以根据方法的参数生成一个唯一的缓存键,即使参数无法正确序列化,仍然能够从缓存中获取结果。

除了自定义的缓存键生成器,还可以通过其他方式解决方法仍然执行的问题。例如,可以考虑使用更合适的缓存注解参数配置,或者使用其他缓存框架来代替Spring的缓存功能。

总而言之,Spring的@Cacheable注解可以提供方法级别的缓存功能,但在某些情况下仍然会执行方法并计算结果。通过使用自定义的缓存键生成器等方式,我们可以解决方法仍然执行的问题,并提高系统的性能和响应速度。