Understanding dynamic proxies in Java with a practical example -- Service retry example
We earlier looked at Java dynamic proxy class example -- Performance testing your Java application.
Design pattern: If you are asked to describe or talk about a design pattern, you could mention this dynamic proxy class as a proxy design pattern. Many pick either singleton or factory design pattern. It would be nicer to pick something other than these two common patterns. Some interviewers specifically ask you to pick anything except factory and singleton design pattern.
In real life applications, you need to retry services that fail. Let's us this retry service scenario to demonstrate dynamic proxy design pattern in Java.
Step 1: Create a dummy service to emulate an internal or external service with outage.
public interface DummyService { abstract void execute(); }
Step 2: The dummy service implementation that emulates failure every time except every 3rd call.
public class DummyServiceImpl implements DummyService { private int count = 0 ; public void execute() { count++; if(count % 3 == 0){ System.out.println ("Executing service ............. "); } else { throw new RuntimeException("Service Cannot be accessed ..... "); } } }
Step 3: Write a Retry service class using the dynamic proxy pattern, which acts as a proxy to retry services on its delegate i.e. DummyService. The service invoker can specify the retry count.
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class RetryProxy<T> implements InvocationHandler { final T delegate; // underlying object int retryCount; //create a proxy public static Object newInstance(Object obj, int retryCount) { return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new RetryProxy(obj, retryCount)); } private RetryProxy(T underlying, int retryCount) { this.delegate = underlying; this.retryCount = retryCount; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { int retries = 0; boolean completed = false; Object ret = null; while (!completed) { try { ret = method.invoke(delegate, args); completed = true; } catch (Exception e) { retries++; if (retries > retryCount) { completed = true; throw e; } System.out.println("Retrying the service. Retry count " + retries); } } return ret; } }
Step 4: The test class to invoke the DummyService via its proxy.
public class DummyServiceInvocationTest { public static void main(String[] args) { DummyServiceInvocationTest test = new DummyServiceInvocationTest(); test.method1(); } public void method1() { DummyService service = (DummyService) RetryProxy.newInstance(new DummyServiceImpl(), 1); service.execute(); } }
Output:
Retrying the service. Retry count 1 Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at com.sun.proxy.$Proxy0.execute(Unknown Source) at DummyServiceInvocationTest.method1(DummyServiceInvocationTest.java:13) at DummyServiceInvocationTest.main(DummyServiceInvocationTest.java:8) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491) at RetryProxy.invoke(RetryProxy.java:28) ... 3 more Caused by: java.lang.RuntimeException: Service Cannot be accessed ..... at DummyServiceImpl.execute(DummyServiceImpl.java:12) ... 8 more
Increase the number of recounts to 3
public void method1() { DummyService service = (DummyService) RetryProxy.newInstance(new DummyServiceImpl(), 3); service.execute(); }
Output:
Retrying the service. Retry count 1 Retrying the service. Retry count 2 Executing service .............
Labels: design pattern
0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home