In a recent project, we still have to use SOAP webservices and I wanted to apply some resilience pattern such as retry to my project.
Also a collegue just presented a java library called resilience4j so I wanted to use that one.
Of course, there are a lot of other possibilites like using other libraries (like Hystrix) or applying the sidecar pattern outside of my application in a cluster.
As you can see in the documentation, resilience4j is build for functional programming style and it supports some functional interfaces
which can be decorated to apply the retry mechanism to the function invocation. In the examples, you can always find a simple setup to pass the supplier and decorate it only for the particular method.
In my use case, I do not want to write the decoration code for each and every method (or function). I have a third party WSDL, generated the webservice interface and port via wsimport and now I want to generically apply the retry mechanism to the webservice client. But my solution is not very complicated, it is using a reflection proxy and invocation handler to direcly decorate and execute the method via the Retry classes.
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.Proxy; | |
import io.github.resilience4j.retry.Retry; | |
public final class WebserviceFactory{ | |
static <T> T decorateWithRetryer(final T service, Retry retry) { | |
InvocationHandler invocationHandler = (proxy, method, args) -> retry.executeCheckedSupplier(() -> method.invoke(service, args)); | |
return (T) Proxy.newProxyInstance(service.getClass().getClassLoader(), | |
service.getClass().getInterfaces(), invocationHandler); | |
} | |
} |
This way I am able to decorate my whole service interface.
One note I can make regarding the exception handling: In case of an exception, an InvocationTargetException is thrown. If you want to have the target one, you have to unwrap it.
The source code of my example is available at https://github.com/mwiede/jaxws-resilience4j.