Reputation: 577
I have a microservice that is calling another microservice to see if that microservice is up via Spring Boot Actuator. I'd like to cache the results to avoid having to perform this check every time my microservice is called. So first step would be to cache the the method that performs this check and then have this cache expire after x seconds. So far the first step is not working. I'm expecting to not enter the method that performs the check, but presently I'm entering isAccountConnectorUp() every time. Is there something that I'm missing?
@Service
public class DepositService {
public void getCredit(String message) {
isAccountConnectorUp();
sendRequestToStream(message);
}
@Cacheable(value = "result", key = "#root.method.name", unless = "#result == true")
private static boolean isAccountConnectorUp() {
final String uri = "http://localhost:9996/health";
boolean isUp = false;
RestTemplate restTemplate = new RestTemplate();
try {
String result = restTemplate.getForObject(uri, String.class);
isUp = true;
} catch (ResourceAccessException exception) {
throw new DatabaseException(ACCOUNT_CONNECTOR_IS_DOWN);
}
return isUp;
}
}
I have added @EnableCaching to my application class.
Upvotes: 2
Views: 7922
Reputation: 124471
There are actually 3 things wrong with this code.
private
methodstatic
methodThe @Cacheable
will be applied through the use of AOP. Which when using Spring is by default using proxies. Which means AOP advice will only be applied if a method call passes through the proxy, as you are already inside the proxy, this won't work as it bypasses the proxy.
Now for a proxy-based AOP solution to work the method has to be non-private and not static
. As currently those cannot be proxied.
So basically you are running into all of those 3. The last one is, somewhat easy, to circumvent, by injecting a reference to yourself and call the method on that.
@Service
public class DepositService {
@Autowired
private DepositService self;
public void getCredit(String message) {
self.isAccountConnectorUp();
sendRequestToStream(message);
}
@Cacheable(value = "result", key = "#root.method.name", unless = "#result == true")
public boolean isAccountConnectorUp() {
final String uri = "http://localhost:9996/health";
boolean isUp = false;
RestTemplate restTemplate = new RestTemplate();
try {
String result = restTemplate.getForObject(uri, String.class);
isUp = true;
} catch (ResourceAccessException exception) {
throw new DatabaseException(ACCOUNT_CONNECTOR_IS_DOWN);
}
return isUp;
}
}
If you really don't want to change the visibility and static
nature of the method. Stop using proxy-based AOP and use compile-time weaving or load-time weaving to modify the bytecode of the class. However, this introduces complexity in either your build or how you need to start your application.
NOTE: Your caching doesn't work as there is unless
clause. Which skips caching if the value is true
, and exception won't be cached. So even with caching this won't work as nothing will be effectively cached.
Upvotes: 3
Reputation: 3197
The @Cacheable
will generate a proxy, but it will only work on the public method. Also, as mentioned in the comments, the proxy will not work on the self-call method.
Upvotes: 0