Lad os koge det lidt ned. Din applikation bruger caching (implementeret med Redis). Hvis Redis-forbindelsen er forældet/lukket eller på anden måde, så ønsker du, at applikationen skal omgå caching og (formodentlig) gå direkte til et underliggende datalager (f.eks. RDBMS). Applikationstjenestelogikken ligner muligvis...
@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);
}
...
}
Det eneste, der betyder noget i Spring cores Caching Abstraktion for at fastslå en Cache "miss" er, at den returnerede værdi er null. Som sådan vil Spring Caching Infrastructure derefter fortsætte med at kalde den faktiske Service-metode (dvs. getCustomer). Husk på returneringen af getCustomerRepo().load(customerId)-kaldet, at du også skal håndtere det tilfælde, hvor Spring's Caching Infrastructure nu forsøger at cache værdien.
I en ånd af holde det enkelt , vi vil undvære AOP, men du burde også kunne opnå dette ved at bruge AOP (dit valg).
Alt hvad du (bør) har brug for er en "brugerdefineret" RedisCacheManager, der udvider SDR CacheManager-implementeringen, noget som...
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;
}
}
}
}
Så hvis Redis ikke er tilgængelig, er det måske bedste, du kan gøre, at logge problemet og fortsætte med at lade tjenestekaldet ske. Det er klart, at dette hæmmer ydeevnen, men det vil i det mindste øge bevidstheden om, at der eksisterer et problem. Det er klart, at dette kunne bindes til et mere robust notifikationssystem, men det er et råt eksempel på mulighederne. Det vigtige er, at din tjeneste forbliver tilgængelig, mens de andre tjenester (f.eks. Redis), som applikationstjenesten afhænger af, kan have fejlet.
I denne implementering (i forhold til min tidligere forklaring) valgte jeg at uddelegere til den underliggende, faktiske RedisCache-implementering for at lade Undtagelsen opstå, så vel vidende at der eksisterer et problem med Redis, og så du kan håndtere Undtagelsen korrekt. Men hvis du er sikker på, at undtagelsen er relateret til et forbindelsesproblem ved inspektion, kan du returnere "null" for at lade Spring Caching Infrastructure fortsætte, som om det var en Cache "miss" (dvs. dårlig Redis Connection ==Cache miss, i dette tilfælde).
Jeg ved, at noget som dette burde hjælpe dit problem, da jeg byggede en lignende prototype af en "brugerdefineret" CacheManager-implementering til GemFire og en af Pivotals kunder. I den særlige UC måtte cachen "miss" udløses af en "forældet version" af applikationsdomæneobjektet, hvor produktionen havde en blanding af nyere og ældre applikationsklienter, der forbinder til GemFire gennem Spring's Caching Abstraction. Applikationsdomænets objektfelter vil for eksempel ændre sig i nyere versioner af appen.
I hvert fald, håber dette hjælper eller giver dig flere ideer.
Skål!