Java Dynamic Proxy

本文介绍如何使用Java动态代理实现日志拦截器及接口适配器,通过具体代码示例展示了两种常见应用场景:作为简单的日志拦截器记录方法调用信息,以及作为不同接口间的简单适配器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
		Comparable<String> obj = (Comparable<String>) 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值