SoFunction
Updated on 2025-05-22

Solutions to continue calling the original method when Redis is out of operation or other reasons cannot be connected or continue to call the original method if Redis is not connected.

@Cacheable annotation Redis, Redis is down or cannot connect to other reasons. Continue to call the original method solution

In Spring Boot applications, we often use​​@Cacheable​​Annotations are used to cache data to improve application performance. When Redis is selected as cache storage, if the Redis service is unavailable for some reason (such as downtime, network problems, etc.), by default,​@Cacheable​​Annotation will throw an exception, causing the entire request to fail. This article will explore how to make​@Cacheable​​Annotation continues to call the original method to ensure the availability and stability of the service.

1. Problem background

1.1 Basic use of @Cacheable annotation

​@Cacheable​​is annotation provided by the Spring framework to identify the results of a method that need to be cached. When this method is called, Spring will first check whether the corresponding data exists in the cache. If it exists, it will directly return the data in the cache; if it does not exist, it will execute the method and store the result in the cache.

1.2 The impact of Redis downtime

When Redis service goes down or there is a problem with the network connection,​@Cacheable​​Annotation An exception is thrown when trying to access Redis, e.g.​​​. This will cause method calls to fail, affecting user experience and system stability.

2. Solution

2.1 Using a custom exception handler

You can catch Redis connection exceptions through a custom exception handler and continue to call the original method when the exception is caught. The specific steps are as follows:

2.1.1 Create a custom exception handler

First, create a custom exception handler class that handles Redis connection exceptions.

import ;
import ;
import ;
public class CustomCacheErrorHandler implements CacheErrorHandler {
    @Override
    public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
        // Handle exceptions when reading cache        ("Cache get error: " + ());
    }
    @Override
    public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
        // Handle exceptions when writing to cache        ("Cache put error: " + ());
    }
    @Override
    public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
        // Handle exceptions when clearing cache        ("Cache evict error: " + ());
    }
    @Override
    public void handleCacheClearError(RuntimeException exception, Cache cache) {
        // Handle exceptions when clearing cache        ("Cache clear error: " + ());
    }
}

2.1.2 Configuring a custom exception handler

In Spring Boot configuration file, configure a custom exception handler.

import ;
import ;
import ;
@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CustomCacheErrorHandler customCacheErrorHandler() {
        return new CustomCacheErrorHandler();
    }
}

2.2 Using the unless attribute of @Cacheable

​@Cacheable​​Annotation provides a​unless​​Properties, you can decide whether to store the result in the cache after the cache operation is successful. Although this property cannot directly solve the problem of Redis downtime, similar effects can be achieved in combination with other logic.

2.3 Using the cache-null-values ​​attribute of @Cacheable

Settings​@Cacheable​​Annotated​cache-null-values​​Properties are​false​, so that even if Redis is not available, it will not be​null​​The value is stored in the cache.

@Cacheable(value = "myCache", cacheNullValues = false)
public User getUserById(Long id) {
    return (id).orElse(null);
}

2.4 Using the downgrade strategy

When Redis is not available, a downgrade strategy can be adopted, such as getting data directly from the database. This can be achieved through a custom cache manager.

import ;
import ;
import ;
import ;
import ;
import ;
@Configuration
public class CustomCacheManager {
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("myCache") {
            @Override
            public Cache getCache(String name) {
                Cache cache = (name);
                if (cache == null) {
                    // If Redis is not available, use local cache                    cache = new ConcurrentMapCache(name);
                }
                return cache;
            }
        };
    }
}

We can ensure that when Redis is not available​@Cacheable​​​Annotation continues to call the original method, thereby improving the stability and usability of the system. Specific implementation methods include custom exception processors and usage​unless​and​cache-null-values​​Properties, and downgrade policies. When using the Spring framework to combine Redis to implement cache function, if Redis fails or cannot connect to Redis due to other reasons, you can configure it​CacheManager​​To implement calls that automatically fall back to the original method when the cache is unavailable. This ensures the availability and stability of the system.

Here is a specific implementation example:

Add dependencies: First make sure that you have added Spring Boot and Redis related dependencies to your project.

<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

Configure Redis connection:existConfigure Redis connection information in the

=localhost
=6379

Custom CacheManager: Create a custom oneCacheManager, where to deal with cases where Redis is not available.

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .GenericJackson2JsonRedisSerializer;
import ;
import ;
import ;
import ;
@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration config = ()
                .entryTtl((1)) // Set the default expiration time                .serializeValuesWith((new GenericJackson2JsonRedisSerializer()));
        Map&lt;String, RedisCacheConfiguration&gt; cacheConfigurations = new HashMap&lt;&gt;();
        ("myCache", config);
        return new FallbackRedisCacheManager(redisConnectionFactory, config, cacheConfigurations);
    }
}

Implement FallbackRedisCacheManager: Create a custom oneCacheManager, fallback to memory cache when Redis is unavailable.

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class FallbackRedisCacheManager extends RedisCacheManager {
    private final CacheManager fallbackCacheManager;
    public FallbackRedisCacheManager(RedisConnectionFactory connectionFactory, RedisCacheConfiguration defaultCacheConfiguration, Map<String, RedisCacheConfiguration> initialCacheConfigurations) {
        super(connectionFactory, defaultCacheConfiguration, initialCacheConfigurations);
        SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
        ((new ConcurrentMapCache("fallbackCache")));
        ();
         = simpleCacheManager;
    }
    @Override
    public Cache getCache(String name) {
        try {
            return (name);
        } catch (RedisConnectionFailureException e) {
            return (name);
        }
    }
}

Use @Cacheable annotation: Used on methods that require cache@Cacheableannotation.

import ;
import ;
@Service
public class MyService {
    @Cacheable(value = "myCache", key = "#id")
    public String getData(String id) {
        // Simulate data acquisition process        ("Fetching data from database for ID: " + id);
        return "Data for ID: " + id;
    }
}

With the above configuration, when Redis is not available,​FallbackRedisCacheManager​Will be captured​RedisConnectionFailureException​Exception and fallback to memory cache. This ensures that even if Redis goes down, the system will still run normally and return data. When using Spring Cache and Redis, if Redis has downtime or connection problems, you can configure it through​CacheManager​and implement custom​CacheErrorHandler​​To ensure that the business logic can run normally even if the cache is unavailable. Here is a detailed solution example:

1. Add dependencies

First, make sure that you have added dependencies for Spring Boot Starter Cache and Spring Boot Starter Data Redis in your project:

<dependencies>
    <dependency>
        <groupId></groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId></groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

2. Configure RedisTemplate

Configuration​RedisTemplate​​Storage objects using JSON serialization:

import ;
import ;
import ;
import ;
import .GenericJackson2JsonRedisSerializer;
import ;
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        (connectionFactory);
        (new StringRedisSerializer());
        (new GenericJackson2JsonRedisSerializer());
        (new StringRedisSerializer());
        (new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

3. Configure CacheManager

Configuration​CacheManager​​Use Redis as cache storage:

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = ()
                .entryTtl((60)) // Set the cache expiration time to 60 minutes                .disableCachingNullValues();
        return (connectionFactory)
                .cacheDefaults(config)
                .build();
    }
}

4. Implement a custom CacheErrorHandler

Implement custom​CacheErrorHandler​, so that the cache operation fails:

import ;
import ;
import ;
import ;
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
    @Override
    public CacheErrorHandler errorHandler() {
        return new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                // Handle cache read errors                ("Cache get error: " + ());
            }
            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
                // Handle cache write errors                ("Cache put error: " + ());
            }
            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
                // Handle cache deletion error                ("Cache evict error: " + ());
            }
            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) {
                // Handle cache clear error                ("Cache clear error: " + ());
            }
        };
    }
}

5. Use @Cacheable annotation

Use on methods that require cache​​@Cacheable​​Note:

import ;
import ;
@Service
public class UserService {
    @Cacheable(value = "users", key = "#userId")
    public User getUserById(String userId) {
        // Simulate to obtain user information from the database        ("Fetching user from database: " + userId);
        return new User(userId, "John Doe");
    }
}

6. Test

You can test whether the above configuration is effective by simulating Redis downtime or disconnection. For example, you can temporarily close the Redis service and then call​​getUserById​Method to check whether the data can be returned normally.

Summarize

Through the above configuration, when Redis is unavailable,​CacheErrorHandler​​Exception of cache operation will be caught and error messages will be printed. At the same time, since​@Cacheable​The default behavior of annotations is to call the original method directly when the cache is unavailable, so the business logic will not be affected. This ensures high availability and stability of the system.

This is the article about the solution of Redis crashing when using @Cacheable annotation or other reasons that cannot be connected to the original method. This is all about this article. For more related @Cacheable annotations. Please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!