首页 > 解决方案 > 如果缓存服务器失败,是否可以让应用程序忽略缓存?

问题描述

我有一个具有以下属性的弹簧启动应用程序:

spring.cache.type: redis
spring.redis.host: <hostname>
spring.redis.port: <hostport>

现在,如果远程主机出现故障,应用程序也会因连接错误而失败。在这种情况下,我的缓存不是我的应用程序的核心,但它仅用于性能,我希望 spring 简单地绕过它并转到数据库检索其数据。

我看到这可以通过定义一个自定义的 errorHandler 方法来实现,但为了做到这一点,我必须实现 CachingConfigurer bean……但这也迫使我重写每个方法(例如缓存管理器、缓存解析器、ecc. )。

@Configuration
public class CacheConfiguration implements CachingConfigurer{

@Override
public CacheManager cacheManager() {
    // TODO Auto-generated method stub
    return null;
}

@Override
public CacheResolver cacheResolver() {
    // TODO Auto-generated method stub
    return null;
}
...
@Override
public CacheErrorHandler errorHandler() {
    // the only method I need, maybe
    return null;
}

我想避免这种情况......我只需要一种方法来告诉spring“缓存崩溃了,但没关系:假装你根本没有缓存”

标签: javaspring-bootspring-data-redisspring-cache

解决方案


@Phate - 绝对!我刚刚回答了一个相关问题(可能),使用 Apache Geode 或 Pivotal GemFire 作为具有 Spring 缓存抽象的 Spring Boot 应用程序中的缓存提供程序。

在那篇文章中,我没有完全禁用缓存,而是将 GemFire/Geode 切换为仅在本地模式下运行(GemFire/Geode 的可能配置)。但是,如果需要,可以应用相同的技术来完全禁用缓存。

本质上,在 Spring Boot 和 Spring 通常开始评估应用程序的配置之前,您需要一个预处理步骤。

在我的示例中,我实现了一个自定义 Spring Condition来检查集群(即服务器)的可用性。然后我将其应用于Condition@Configuration班级。

在 Spring Boot 的情况下,当 Spring Boot在应用程序的类路径上有效地看到(以及参见此处)Redis 和 Spring Data Redis时,它会为 Redis(作为存储和缓存提供程序)应用自动配置。因此,本质上,Redis 仅在“条件”为true时才作为缓存提供程序启用,主要是 您的应用程序配置声明了一个bean ,您的责任。RedisConnectionFactory

那么,这会是什么样子呢?

像我的 Apache Geode & Pivotal GemFire custom Spring Condition一样,您可以为 Redis 实现类似的 Condition,例如:

static RedisAvailableCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, 
            AnnotatedTypeMetadata annotatedTypeMetadata) {

        // Check the available of the Redis server, such as by opening a Socket
        // connection to the server node.
        // NOTE: There might be other, more reliable/robust means of checking 
        // the availability of a Redis server in the Redis community.
        Socket redisServer;

        try {

            Environment environment = conditionContext.getEnvironment();

            String host = environment.getProperty("spring.redis.host");
            Integer port = environment.getProperty("spring.redis.port", Integer.class);

            SocketAddress redisServerAddress = new InetSocketAddress(host, port);

            redisServer = new Socket();
            redisServer.connect(redisServerAddress);

            return true;
        }
        catch (Throwable ignore) {

            System.setProperty("spring.cache.type", "none");

            return false;
        }
        finally {
            // TODO: You need to implement this method yourself.
            safeCloseSocket(redisServer);
        }
    }
}

此外,我还将 设置spring.cache.typeNONE,以确保在 Redis 不可用的情况下将缓存呈现为无操作。 在这里NONE更详细地解释。

当然,您也可以使用备用缓存选项,使用其他一些缓存提供程序(例如简单的ConcurrentHashMap,但我将其留给您作为练习)。向前...

然后,在定义了RedisConnectionFactorybean 的 Spring Boot 应用程序配置类中(正如 Spring Boot 的自动配置所期望的那样),Condition使用 Spring 的@Conditiional注释添加这个自定义,如下所示:

@Confgiuration
@Conditional(RedisAvailableCondition.class);
class MyRedisConfiguration {

    @Bean
    RedisConnectionFactory redisConnectionFactory() {
        // Construct and return new RedisConnectionFactory
    }
}

这应该可以有效地处理 Redis 不可用的情况。

免责声明:我自己没有对此进行测试,但基于我的 Apache Geode/Pivotal GemFire 示例,该示例确实有效。因此,也许,通过一些调整,这将满足您的需求。它也应该给你一些想法。

希望这可以帮助!

干杯!


推荐阅读