1) Act as a simple log interceptor:
public class DynamicProxy { private static final Logger logger = Logger.getLogger(DynamicProxy.class); @SuppressWarnings("unchecked") @Test public void useProxyTest() { String str = "Hello world"; LoggingInvocationHandler handler = new LoggingInvocationHandler(str); Comparableobj = (Comparable ) Proxy.newProxyInstance( this.getClass().getClassLoader(), new Class[]{Comparable.class}, handler); obj.compareTo("Yes"); } public static class LoggingInvocationHandler implements InvocationHandler { private Object targetObject; public LoggingInvocationHandler(Object targetObject) { this.targetObject = targetObject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { logger.info(String.format("Invoking method: [%s], args: [%s]", method.getName(), Lists.newArrayList(args))); return method.invoke(targetObject, args); } } }
2) Act as a simple adapter between two different interfaces:
public class DynamicProxy { private static final Logger logger = Logger.getLogger(DynamicProxy.class); public static interface GreetV1 { String greet(String name, String gender) throws IOException; } public static interface GreetV2 { String greet(String username); } public class GreetAdapter implements InvocationHandler { private GreetV1 greetInstance; public GreetAdapter(GreetV1 greetInstance) { super(); this.greetInstance = greetInstance; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if ("greet".equals(methodName)) { String username = (String) args[0]; String name = lookupName(username); String gender = lookupGender(username); logger.info(proxy.getClass()); // ((GreetV2)proxy).greet(username); try { return greetInstance.greet(name, gender); } catch (Exception e) { throw new RuntimeException(e); } } else { return method.invoke(greetInstance, args); } } private String lookupGender(String username) { // Dummy return "Male"; } private String lookupName(String username) { // Dummy return "Yang"; } } @Test public void adapterTest() { GreetAdapter adapter = new GreetAdapter(new GreetV1() { @Override public String greet(String name, String gender) throws IOException { return String.format("Hello %s[%s]", name, gender); } }); GreetV2 greetV2 = (GreetV2) Proxy.newProxyInstance(this.getClass() .getClassLoader(), new Class[]{GreetV2.class}, adapter); assertEquals("Hello Yang[Male]", greetV2.greet("Yang, Kunlun")); logger.info(greetV2.getClass()); } }
The first argument "proxy" in method invoke() is actually the "greetV2" instance.
greetV2 is indeed an instance of an anonymous class who extends java.lang.reflect.Proxy and implements GreetV2 interface.
And it has an InvocationHandler property which points to "adapter".
If we decomment the "((GreetV2)proxy).greet(username)", the "java.lang.StackOverflowError" will occur.
See simplified Proxy code below:
public class Proxy implements java.io.Serializable { protected InvocationHandler h; protected Proxy(InvocationHandler h) { this.h = h; // As the dynamically generated class extends Proxy, therefore it has this InvocationHandler property. } public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) { final Constructor> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; return newInstance(cons, ih); // creates a new instance that extends java.lang.reflect.Proxy and implements the interfaces passed in. } }
Reference Links:
http://guojuanjun.blog.51cto.com/277646/1221281
http://paddy-w.iteye.com/blog/841798