【问题标题】:Using a Spring CacheManager from dependent jar使用依赖 jar 中的 Spring CacheManager
【发布时间】:2015-04-19 05:57:41
【问题描述】:

我有几个 WAR 项目,其中包含对某个实用程序 JAR 项目的依赖项。我希望能够通过使用 spring 的 @Cacheable 注释来缓存实用程序项目中的某些方法,所以我尝试在实用程序项目上创建一个配置文件,我可以在其中定义一个可以处理方法缓存的 CacheManager bean。配置文件如下所示:

(请注意,我使用的是 Redis 缓存实现,但其他缓存提供程序的 spring 配置应该非常相似)

@Configuration
@EnableCaching
public class RedisConfig {

    @Value("${redis.hostUrl}")
    private String hostUrl = null;

    @Value("${redis.port}")
    private Integer port = null;

    @Value("${redis.defaultExpiration}")
    private Integer defaultExpiration = null;


    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory = new JedisConnectionFactory();
        // Defaults
        redisConnectionFactory.setHostName(hostUrl);
        redisConnectionFactory.setPort(port);
        return redisConnectionFactory;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory cf) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(cf);
        return redisTemplate;
    }

    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);

        // Number of seconds before expiration. Defaults to unlimited (0)
        cacheManager.setDefaultExpiration(defaultExpiration);

        cacheManager.setUsePrefix(true);

        List<String> cacheNames = new ArrayList<String>();
        cacheNames.add("testing");
        cacheManager.setCacheNames(cacheNames);
        return cacheManager;
    }
}

我很确定配置本身没有问题,因为我在其他 WAR 模块中有类似的配置文件,并且缓存在这些模块上运行良好。但是,由于这是一个由其他模块加载的 JAR,我猜测 CacheManager 没有被 Spring 拾取。

在依赖于 utils 项目的项目 A 中,我有一个类似以下的方法(为简单起见进行了编辑;忽略无效语法):

@RequestMapping(...)
@ResponseBody
public Dto methodA(...) {

    //The relevant part
    testCachedMethod(value);
    cachedMethodFromProjectB(value);

}

@Cacheable(value="testing")
public String testCachedMethod(String value) {
    return value;
}

项目 B 是另一个 WAR,它有自己的 CacheManager(不绑定到 utils),并且使用 @Cacheable 缓存了类似的方法。如果我点击项目 A 的方法 A,则项目 B 中的缓存会正确存储,但项目 A 中的 cachedMethod 不会在缓存中存储任何内容(也不会使用 @Cacheable 注释的 utils 项目中的方法)。我也尝试了另一种方法,直接在项目 A 上创建 CacheManager,但它也无法缓存 utils 项目中的注释方法(我更喜欢在 utils 项目中声明管理器,以便它可以被其他模块重用)。

我知道 Spring 正在正确初始化 utils 项目中的 bean,因为如果项目 A 的上下文的属性占位符未从缓存配置文件中找到 @Value 注释的属性文件,则项目 A 将无法运行。所以我想 CacheManager bean 在那里,但不知何故它不起作用。关于我做错了什么的任何想法,或者是否可以使用依赖 JAR 中的 CacheManager(如果可能,使用 Java 配置)?我正在使用 Spring 3.2.0.RELEASE。

这几天一直在尝试解决这个问题,因此非常感谢您的帮助。

【问题讨论】:

    标签: java spring caching jar redis


    【解决方案1】:

    原来是 spring 缓存抽象的默认代理模式存在问题。缓存注释不起作用的所有方法都被同一对象中的其他方法调用。我可以使用 CacheManager bean 上的 @Autowire 正确操作依赖 jar 项目中的缓存并手动执行缓存操作。虽然应该可以通过启用 AspectJ 编织模式来使用注释,但我不想通过处理依赖模块中的编织来增加更多复杂性。

    【讨论】:

    • 我遇到了类似的问题,将缓存方法从同一个对象中移出正是我们所需要的。感谢您的跟进,因为我完全忘记了 spring 代理行为,这使我免于进一步沮丧。
    • 是的,将@Cacheable 方法移到调用方法类之外并且自动装配有效。但这是一种好方法吗?
    猜你喜欢
    • 2011-07-19
    • 2019-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    相关资源
    最近更新 更多