Sprowadźmy to trochę. Twoja aplikacja korzysta z pamięci podręcznej (zaimplementowanej w Redis). Jeśli połączenie Redis jest nieaktualne/zamknięte lub w inny sposób, chcesz, aby aplikacja pomijała buforowanie i (prawdopodobnie) przechodziła bezpośrednio do bazowego magazynu danych (np. RDBMS). Logika usługi aplikacji może wyglądać podobnie do...
@Service
class CustomerService ... {
@Autowired
private CustomerRepository customerRepo;
protected CustomerRepository getCustomerRepo() {
Assert.notNull(customerRepo, "The CustomerRepository was not initialized!");
return customerRepo;
}
@Cacheable(value = "Customers")
public Customer getCustomer(Long customerId) {
return getCustomerRepo().load(customerId);
}
...
}
Jedyne, co ma znaczenie w Caching Abstraction Spring Core, aby upewnić się, że pamięć podręczna jest „chybiona”, to to, że zwrócona wartość jest null. W związku z tym Spring Caching Infrastructure będzie następnie wywoływać właściwą metodę Service (tj. getCustomer). Pamiętaj o zwrocie wywołania getCustomerRepo().load(customerId), musisz również zająć się przypadkiem, w którym Spring Caching Infrastructure próbuje teraz buforować wartość.
W duchu zachowania prostoty , obejdziemy się bez AOP, ale powinieneś być w stanie to osiągnąć również za pomocą AOP (Twój wybór).
Wszystko, czego (powinnaś) potrzebować, to "niestandardowy" RedisCacheManager rozszerzający implementację SDR CacheManager, coś w rodzaju...
package example;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheManager;
...
class MyCustomRedisCacheManager extends RedisCacheManager {
public MyCustomerRedisCacheManager(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) {
Assert.notNull(redisCache, "'delegate' must not be null");
this.delegate = redisCache;
}
@Override
public Cache.ValueWrapper get(Object key) {
try {
delegate.get(key);
}
catch (Exception e) {
return handleErrors(e);
}
}
@Override
public void put(Object key, Object value) {
try {
delegate.put(key, value);
}
catch (Exception e) {
handleErrors(e);
}
}
// 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 {
if (e instanceof <some RedisConnection Exception type>) {
// log the connection problem
return null;
}
else if (<something different>) { // act appropriately }
...
else {
throw e;
}
}
}
}
Jeśli więc Redis jest niedostępny, być może najlepszym, co możesz zrobić, to zarejestrować problem i pozwolić na wywołanie usługi. Oczywiście utrudni to wydajność, ale przynajmniej podniesie świadomość istnienia problemu. Oczywiście można to powiązać z solidniejszym systemem powiadomień, ale jest to zgrubny przykład możliwości. Ważną rzeczą jest to, że Twoja usługa pozostaje dostępna, podczas gdy inne usługi (np. Redis), od których zależy usługa aplikacji, mogły ulec awarii.
W tej implementacji (w porównaniu z moim poprzednim wyjaśnieniem) zdecydowałem się delegować do podstawowej, rzeczywistej implementacji RedisCache, aby pozwolić na wystąpienie Wyjątku, a następnie dobrze wiedzieć, że istnieje problem z Redis i aby można było odpowiednio poradzić sobie z Wyjątkiem. Jeśli jednak masz pewność, że wyjątek jest związany z problemem z połączeniem podczas inspekcji, możesz zwrócić wartość „null”, aby Spring Caching Infrastructure działał tak, jakby był „pominięciem” pamięci podręcznej (tj. Złe połączenie Redis ==Brak pamięci podręcznej, w tym przypadku).
Wiem, że coś takiego powinno pomóc w Twoim problemie, ponieważ zbudowałem podobny prototyp „niestandardowej” implementacji CacheManager dla GemFire i jednego z klientów Pivotal. W tej konkretnej UC „chybiona” pamięć podręczna musiała zostać wywołana przez „nieaktualną wersję” obiektu domeny aplikacji, w której produkcja zawierała mieszankę nowszych i starszych klientów aplikacji łączących się z GemFire przez Spring's Caching Abstraction. Na przykład pola obiektu domeny aplikacji zmienią się w nowszych wersjach aplikacji.
W każdym razie miej nadzieję, że to pomoże lub da ci więcej pomysłów.
Pozdrawiam!