我使用的是Spring-data-redis缓存(1.6.1),Jredis Client 2.7.3。我们希望启用故障转移。如果redis服务器关闭,我希望应用程序继续运行
1)如果我使用spring-data xml配置,redis缓存工作正常。它调用后端,缓存数据,然后在第二次调用时不调用后端。但是,如果服务器使用xml配置关闭并返回null以便应用程序继续工作,我不知道如何捕获Redis异常。文档不够。 (此解决方案不起作用)
2)我已经使用Java配置了redis缓存,在这种情况下,我能够捕获故障转移,但是Spring-data-redis继续调用后端数据库方法,即使redis缓存正在工作。所以它应该调用后端方法并缓存数据。第二次调用不应该返回到后端数据库。
所以它是缓存并在所有请求上调用后端数据库方法。
我想知道是否有人遇到过这个问题。或者任何关于如果后端Redis服务器关闭时如何故障转移spring-data-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;
// }
// }
}
}
答案 0 :(得分:0)
我的坏..我解决了这个问题。我从get函数返回null
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;
// }
// }
}
}
}