background

  • In the project, data is cached using @cacheable. Found: When Redis goes down, the @cacheable annotation method does not cache collisions, but instead throws an exception. Such exceptions cause the service to become unavailable.

Cause analysis,

  • Caching is enabled via @enablecaching, so look at the comments for @enablecaching

  • Through the class notes can be found @ EnableCaching, spring is the core of the cache configuration interface is: org. Springframework. Cache. The annotation. CachingConfigurer
/**
 * Interface to be implemented by @{@link org.springframework.context.annotation.Configuration
 * Configuration} classes annotated with @{@link EnableCaching} that wish or need to
 * specify explicitly how caches are resolved and how keys are generated for annotation-driven
 * cache management. Consider extending {@link CachingConfigurerSupport}, which provides a
 * stub implementation of all interface methods.
 *
 * <p>See @{@link EnableCaching} for general examples and context; see
 * {@link #cacheManager()}, {@link #cacheResolver()} and {@link #keyGenerator()}
 * for detailed instructions.
 *
 * @author Chris Beams
 * @author Stephane Nicoll
 * @since 3.1
 * @see EnableCaching
 * @see CachingConfigurerSupport
 */
public interface CachingConfigurer {

	/**
	 * Return the cache manager bean to use for annotation-driven cache
	 * management. A default {@link CacheResolver} will be initialized
	 * behind the scenes with this cache manager. For more fine-grained
	 * management of the cache resolution, consider setting the
	 * {@link CacheResolver} directly.
	 * <p>Implementations must explicitly declare
	 * {@link org.springframework.context.annotation.Bean @Bean}, e.g. * <pre class="code"> * &#064; Configuration * &#064; EnableCaching * public class AppConfig extends CachingConfigurerSupport { * &#064; Bean // important! * & # 064; Override * public CacheManager cacheManager() { * // configure and return CacheManager instance * } * // ... * } * </pre> * See @{@link EnableCaching} for more complete examples.
	 */
	CacheManager cacheManager(a);

	/**
	 * Return the {@link CacheResolver} bean to use to resolve regular caches for
	 * annotation-driven cache management. This is an alternative and more powerful
	 * option of specifying the {@link CacheManager} to use.
	 * <p>If both a {@link #cacheManager()} and {@code #cacheResolver()} are set,
	 * the cache manager is ignored.
	 * <p>Implementations must explicitly declare
	 * {@link org.springframework.context.annotation.Bean @Bean}, e.g. * <pre class="code"> * &#064; Configuration * &#064; EnableCaching * public class AppConfig extends CachingConfigurerSupport { * &#064; Bean // important! * & # 064; Override * public CacheResolver cacheResolver() { * // configure and return CacheResolver instance * } * // ... * } * </pre> * See {@link EnableCaching} for more complete examples.
	 */
	CacheResolver cacheResolver(a);

	/**
	 * Return the key generator bean to use for annotation-driven cache management.
	 * Implementations must explicitly declare
	 * {@link org.springframework.context.annotation.Bean @Bean}, e.g. * <pre class="code"> * &#064; Configuration * &#064; EnableCaching * public class AppConfig extends CachingConfigurerSupport { * &#064; Bean // important! * & # 064; Override * public KeyGenerator keyGenerator() { * // configure and return KeyGenerator instance * } * // ... * } * </pre> * See @{@link EnableCaching} for more complete examples.
	 */
	KeyGenerator keyGenerator(a);

	/**
	 * Return the {@link CacheErrorHandler} to use to handle cache-related errors.
	 * <p>By default,{@link org.springframework.cache.interceptor.SimpleCacheErrorHandler}
	 * is used and simply throws the exception back at the client.
	 * <p>Implementations must explicitly declare
	 * {@link org.springframework.context.annotation.Bean @Bean}, e.g. * <pre class="code"> * &#064; Configuration * &#064; EnableCaching * public class AppConfig extends CachingConfigurerSupport { * &#064; Bean // important! * & # 064; Override * public CacheErrorHandler errorHandler() { * // configure and return CacheErrorHandler instance * } * // ... * } * </pre> * See @{@link EnableCaching} for more complete examples.
	 */
	CacheErrorHandler errorHandler(a);

}
Copy the code
  • The errorHandler method of this interface can be used to configure the handling mode of exceptions. Through the comments can be found on the way, the default CacheErrorHandler implementation class is org springframework. Cache. The interceptor. SimpleCacheErrorHandler
/**
 * A simple {@link CacheErrorHandler} that does not handle the
 * exception at all, simply throwing it back at the client.
 *
 * @author Stephane Nicoll
 * @since4.1 * /
public class SimpleCacheErrorHandler implements CacheErrorHandler {

	@Override
	public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
		throw exception;
	}

	@Override
	public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
		throw exception;
	}

	@Override
	public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
		throw exception;
	}

	@Override
	public void handleCacheClearError(RuntimeException exception, Cache cache) {
		throwexception; }}Copy the code
  • The SimpleCacheErrorHandler class comment makes it clear that the SimpleCacheErrorHandler class does nothing about the cache exception and simply throws it to the client. Therefore, by default, when the Redis server is abnormal, normal services are directly blocked

The solution

  • As you can see from the above analysis, you can interfere with @Cacheable’s exception handling logic by customizing CacheErrorHandler. The specific code is as follows:
public class RedisConfig extends CachingConfigurerSupport {

    /** * redis data operation exception handling. The processing logic of this method is: Error information is printed in the log, but permission is allowed. * Ensure that redis server connection and other problems will not affect the normal operation of the program */
    @Override
    public CacheErrorHandler errorHandler(a) {
        return new CacheErrorHandler() {
            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
                handleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                handleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
                handleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) {
                handleRedisErrorException(exception, null); }}; }protected void handleRedisErrorException(RuntimeException exception, Object key) {
        log.error(Redis exception: key=[{}], key, exception); }}Copy the code