Laten we dit een beetje inkoken. Uw applicatie maakt gebruik van caching (geïmplementeerd met Redis). Als de Redis-verbinding oud/gesloten is of anderszins, dan wil je dat de applicatie caching omzeilt en (vermoedelijk) direct naar een onderliggende datastore gaat (bijv. RDBMS). De logica van de toepassingsservice kan er ongeveer zo uitzien als...
@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);
}
...
}
Het enige dat ertoe doet in Spring core's Caching Abstraction om een cache "misser" vast te stellen, is dat de geretourneerde waarde null is. Als zodanig zal Spring Caching Infrastructure dan doorgaan met het aanroepen van de daadwerkelijke servicemethode (d.w.z. getCustomer). Houd er rekening mee dat bij de terugkeer van de getCustomerRepo().load(customerId)-aanroep, u ook het geval moet afhandelen waarin Spring's Caching-infrastructuur nu probeert de waarde in de cache op te slaan.
In de geest van het simpel houden , we zullen het zonder AOP doen, maar u zou dit ook met AOP moeten kunnen bereiken (uw keuze).
Het enige dat u (zou) nodig hebt, is een "aangepaste" RedisCacheManager die de SDR CacheManager-implementatie uitbreidt, zoiets als...
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;
}
}
}
}
Dus als Redis niet beschikbaar is, kunt u het beste het probleem registreren en doorgaan met het aanroepen van de Service. Het is duidelijk dat dit de prestaties zal belemmeren, maar het zal in ieder geval het bewustzijn vergroten dat er een probleem bestaat. Het is duidelijk dat dit kan worden gekoppeld aan een robuuster meldingssysteem, maar het is een grof voorbeeld van de mogelijkheden. Het belangrijkste is dat uw Service beschikbaar blijft terwijl de andere services (bijv. Redis) waarvan de applicatieservice afhankelijk is, mogelijk zijn mislukt.
In deze implementatie (vs. mijn vorige uitleg) heb ik ervoor gekozen om te delegeren aan de onderliggende, daadwerkelijke RedisCache-implementatie om de uitzondering te laten plaatsvinden, terwijl ik heel goed weet dat er een probleem met Redis bestaat, en zodat je op de juiste manier met de uitzondering kunt omgaan. Als u er echter zeker van bent dat de Uitzondering verband houdt met een verbindingsprobleem bij inspectie, kunt u "null" retourneren om Spring Caching Infrastructure te laten doorgaan alsof het een cache "miss" is (d.w.z. slechte Redis Connection ==Cache miss, in dit geval).
Ik weet dat zoiets je probleem zou moeten helpen, aangezien ik een soortgelijk prototype heb gebouwd van een "aangepaste" CacheManager-implementatie voor GemFire en een van de klanten van Pivotal. In die specifieke UC moest de cache "miss" worden geactiveerd door een "verouderde versie" van het toepassingsdomeinobject waar de productie een mix van nieuwere en oudere toepassingsclients had die verbinding maakten met GemFire via Spring's Caching Abstraction. De objectvelden van het toepassingsdomein zouden bijvoorbeeld veranderen in nieuwere versies van de app.
Hoe dan ook, ik hoop dat dit je helpt of je meer ideeën geeft.
Proost!