Spring-data-redis cache - вызывает бэкэнд-метод, даже если данные кешируются, если я использую CustomizeRedisCacheManager

Я использую кеш Spring-data-redis (1.6.1), Jredis Client 2.7.3. Мы хотим включить аварийное переключение. Если сервер Redis не работает, я хочу, чтобы приложение продолжало работать

1) Если я использовал xml-конфигурацию spring-data, кеш redis работает нормально. Он вызывает бэкэнд, кэширует данные, а затем не вызывает бэкэнд при втором вызове. Однако я не знаю, как зафиксировать исключение Redis, если сервер не работает с использованием конфигурации xml и возвращает значение null, чтобы приложение продолжало работать. Недостаточно документации. (Это решение не работает)

2) Я настроил кеш Redis с использованием Java. В этом случае я могу поймать исключение аварийного переключения, но Spring-data-redis продолжает вызывать метод базы данных backend, даже если кеш Redis работает. Поэтому он должен вызывать внутренний метод и кэшировать данные. Второй вызов не должен возвращаться в базу данных серверной части.

Таким образом, он кэширует и вызывает метод базы данных серверной части для всех запросов.

Мне было интересно, сталкивался ли кто-нибудь с этой проблемой. Или любая идея о том, как выполнить аварийное переключение spring-data-redis, если внутренний сервер Redis не работает.

Я приложил образец кода.

Вот AppConfig.java

Configuration
@EnableCaching
@ComponentScan("com.mkyong.helloworld.service")
@PropertySource("classpath:/redis.properties")
public class AppConfig extends CachingConfigurerSupport{
    private @Value("${redis.host-name}") String redisHostName;
    private @Value("${redis.port}") int redisPort;
//  private @Value("${cache.expire}") long cacheExpire;
//  private @Value("${cache.name}") String cacheName; 


private Log logger = LogFactory.getLog(getClass());

 @Bean
 public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
     return new PropertySourcesPlaceholderConfigurer();
 }

 @Bean
 JedisConnectionFactory jedisConnectionFactory() {
     JedisConnectionFactory factory = new JedisConnectionFactory();
     factory.setHostName(redisHostName);
     factory.setPort(redisPort);
     factory.setUsePool(true);
     return factory;
 }

 @Bean
 RedisTemplate<Object, Object> redisTemplate() {
     RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
     redisTemplate.setConnectionFactory(jedisConnectionFactory());
     return redisTemplate;
 }

 @Bean
 public CacheManager cacheManager() {
//     return new RedisCacheManager(redisTemplate());
//      logger.debug("Calling Redis CustomRedisCacheManager()" );
//     return new CustomRedisCacheManager(redisTemplate());
     logger.debug("START: operation=cacheManager");
     UUID transactionId = UUID.randomUUID();
     long startTime = System.currentTimeMillis();
     long stopTime=0;
     long elapsedTime=0;
     String userTokenCache1="descCache";
     String userTokenCache2="titleCache";
     //Long expiration = environment.getProperty("cache.default.timeout", Long.class);
     Long expiration = 360000L;
     Map<String, Long> expires = new ConcurrentHashMap<>(1);
     expires.put(userTokenCache1, expiration);
     expires.put(userTokenCache2, expiration);
     CustomRedisCacheManager cacheMgr = new CustomRedisCacheManager( redisTemplate() );
     cacheMgr.setExpires(expires);
//   //cacheMgr.setDefaultExpiration(expires);
//   cacheMgr.setCacheNames(Arrays.asList(userTokenCache));
     stopTime = System.currentTimeMillis();
     elapsedTime = stopTime - startTime;
     logger.debug("Cache Name = " + userTokenCache1 + " cacheExpire=" + userTokenCache1 );
     logger.debug("END: transcation_id=" + transactionId + " operation=cacheManager" + " status=Completed, execution_time=" + elapsedTime );

     return cacheMgr;
 }

// @Bean // important!
// @Override
// public CacheErrorHandler errorHandler() {
//     // configure and return CacheErrorHandler instance
//   CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
//      
//      @Override
//      public void handleCachePutError(RuntimeException exception, Cache cache,
//              Object key, Object value) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Unable to save Cache..." );
//      }
//      
//      @Override
//      public void handleCacheGetError(RuntimeException exception, Cache cache,
//              Object key) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Fetching Data from the backend..." );
//      
//      }
//      
//      @Override
//      public void handleCacheEvictError(RuntimeException exception, Cache cache,
//              Object key) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Unable to evict cache..." );
//      }
//      
//      @Override
//      public void handleCacheClearError(RuntimeException exception, Cache cache) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Unable to clear cache..." );
//      }
//  };
//  return cacheErrorHandler;
// }

}

Вот HelloWorldServica.java

@Service
public class HelloWorldService {

    private static final Logger logger = LoggerFactory.getLogger(HelloWorldService.class);

     @Cacheable(value="descCache")
    public String getDesc() {

        logger.debug("getDesc() is executed!");

        return "Gradle + Spring MVC Hello World Example";

    }
     @Cacheable(value="titleCache")
    public String getTitle(String name) {

        logger.debug("getTitle() is executed! $name : {}", name);

        if(StringUtils.isEmpty(name)){
            return "Hello World";
        }else{
            return "Hello " + name;
        }

    }

}

WelcomeController.java

@Controller
public class WelcomeController {

    private final Logger logger = LoggerFactory.getLogger(WelcomeController.class);
    private final HelloWorldService helloWorldService;
    ApplicationContext ctx = null;

   @Autowired
    public WelcomeController(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
        ctx = new AnnotationConfigApplicationContext(AppConfig.class);

   }

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(Map<String, Object> model) {

        logger.debug("index() is executed!");

        model.put("title", helloWorldService.getTitle(""));
        model.put("msg", helloWorldService.getDesc());

        return "index";
    }

    @RequestMapping(value = "/hello/{name:.+}", method = RequestMethod.GET)
    public ModelAndView hello(@PathVariable("name") String name) {

        logger.debug("hello() is executed - $name {}", name);

        ModelAndView model = new ModelAndView();
        model.setViewName("index");

        model.addObject("title", helloWorldService.getTitle(name));
        model.addObject("msg", helloWorldService.getDesc());

        return model;

    }

    class CustomRedisCacheManager extends RedisCacheManager {
    private static Log logger = LogFactory.getLog(CustomRedisCacheManager.class);
    public CustomRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }
    @Override
    public Cache getCache(String name) {
        return new RedisCacheWrapper(super.getCache(name));
    }

    protected static class RedisCacheWrapper implements Cache {
        private final Cache delegate;
        public RedisCacheWrapper(Cache redisCache) {
            logger.debug("Start:RedisCacheWrapper()" );
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            Assert.notNull(redisCache, "'delegate' must not be null");
            this.delegate = redisCache;
            stopTime = System.currentTimeMillis();
            elapsedTime = stopTime - startTime;
            logger.info(" transcation_id=" + transactionId + " operation=RedisCacheWrapper" + " status=Completed, execution_time (ms)=" + elapsedTime );
            logger.debug("End:RedisCacheWrapper()" );

        }
        @Override
        public Cache.ValueWrapper get(Object key) {
            logger.debug("As the Redis Cache server may be down. Unable to save Cache..." );
            try {
                delegate.get(key);
            }
            catch (Exception e) {
                try {
                    return handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
            return null;
        }
        @Override
        public void put(Object key, Object value) {
            try {
                delegate.put(key, value);
            }
            catch (Exception e) {
                try {
                    handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        }
        @Override
        public String getName() {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public Object getNativeCache() {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public <T> T get(Object key, Class<T> type) {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public ValueWrapper putIfAbsent(Object key, Object value) {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public void evict(Object key) {
            // TODO Auto-generated method stub

        }
        @Override
        public void clear() {
            // TODO Auto-generated method stub

        }

        // implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).
        protected <T> T handleErrors(Exception e) throws Exception {
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            logger.debug("Exception Thrown" + e.getMessage() );
            if (e instanceof RuntimeException ) 
            {
                stopTime = System.currentTimeMillis();
                elapsedTime = stopTime - startTime;
                logger.info(" transcation_id=" + transactionId + " operation=Redis Cache" + " status=Redis cahce may be down, return null, cause=" + e.getMessage() + " execution_time=" + elapsedTime );
                return null;
            } else {
                throw e;
            }
//          else if (<something different>) { // act appropriately }
//              else {
//                  throw e;
//              }
//          }
        }

    }

person J Sandhu    schedule 04.01.2016    source источник


Ответы (1)


Моя Плохая .. Я исправил эту проблему. Я возвращал null из функции get

   class CustomRedisCacheManager extends RedisCacheManager {
    private static Log logger = LogFactory.getLog(CustomRedisCacheManager.class);
    public CustomRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }
    @Override
    public Cache getCache(String name) {
        return new RedisCacheWrapper(super.getCache(name));
    }

    protected static class RedisCacheWrapper implements Cache {
        private final Cache delegate;
        public RedisCacheWrapper(Cache redisCache) {
            logger.debug("Start: operation=RedisCacheWrapper" );
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            Assert.notNull(redisCache, "'delegate' must not be null");
            this.delegate = redisCache;
            stopTime = System.currentTimeMillis();
            elapsedTime = stopTime - startTime;
            logger.debug(" transcation_id=" + transactionId + " operation=RedisCacheWrapper" + " status=Completed, execution_time (ms)=" + elapsedTime );
            logger.debug("End: operation=RedisCacheWrapper" );

        }
        @Override
        public Cache.ValueWrapper get(Object key) {
            logger.debug("Start: operation=get(Object key)" );

            System.out.println("Start: get(Object key)" );
            try {
                Cache.ValueWrapper valueWrapper=delegate.get(key);
                System.out.println("End: get(Object key) returning valueWrapper" );
                logger.debug("End: operation=get(Object key)" );
                ***return valueWrapper;***
            }
            catch (Exception e) {
                try {
                    return handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                    return null;
                }
            }

        }
        @Override
        public void put(Object key, Object value) {
            logger.debug("Start: operation=put" );
            try {
                delegate.put(key, value);
                logger.debug("End: operation=put" );
            }
            catch (Exception e) {
                try {
                    handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        }
        @Override
        public String getName() {
            // TODO Auto-generated method stub
            return delegate.getName();
//          return null;
        }
        @Override
        public Object getNativeCache() {
            // TODO Auto-generated method stub
            return delegate.getNativeCache();

//          return null;
        }
        @Override
        public <T> T get(Object key, Class<T> type) {
            // TODO Auto-generated method stub
            return delegate.get(key, type);
            //return null;
        }
        @Override
        public ValueWrapper putIfAbsent(Object key, Object value) {
            // TODO Auto-generated method stub
            return delegate.putIfAbsent(key, value);
        }
        @Override
        public void evict(Object key) {
            // TODO Auto-generated method stub

            logger.info("Carch is evicted");
        }
        @Override
        public void clear() {
            // TODO Auto-generated method stub
            logger.info("Carch is clear");

        }

        // implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).
        protected <T> T handleErrors(Exception e) throws Exception {
            logger.debug("Start: operation=handleErrors" );
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            logger.debug("Exception Thrown" + e.getMessage() );

            if (e instanceof RuntimeException ) 
            {
                stopTime = System.currentTimeMillis();
                elapsedTime = stopTime - startTime;
                logger.debug(" transcation_id=" + transactionId + " operation=handleErrors" + " status=Redis cahce may be down, return null, cause=" + e.getMessage() + " execution_time=" + elapsedTime );
                return null;
            } else {
                logger.debug(" transcation_id=" + transactionId + " operation=handleErrors" + " status=Redis cahce may be down, Some Other exception, cause=" + e.getMessage() + " execution_time=" + elapsedTime );
                throw e;
            }
//          else if (<something different>) { // act appropriately }
//              else {
//                  throw e;
//              }
//          }
        }

    }
}
person J Sandhu    schedule 05.01.2016