- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- public class Test {
- public static void main(String[] args) {
- UserManager target = new UserManagerImpl();
- UserManager proxy = (UserManager) Proxy.newProxyInstance(target.getClass().getClassLoader(),
- target.getClass().getInterfaces(), new UserManagerProxy(target));
- proxy.addUser();
- }
- }
- interface UserManager {
- public void addUser();
- }
- class UserManagerImpl implements UserManager {
- @Override
- public void addUser() {
- System.out.println("add user...");
- }
- }
- class UserManagerProxy implements InvocationHandler {
- private UserManager target;
- public UserManagerProxy(UserManager target) {
- this.target = target;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("check privilege " + proxy);
- method.invoke(target, args);
- return null;
- }
- }
在執行代理處理類的System.out.println("check privilege " + proxy);時候,出現了java.lang.StackOverflowError錯誤。原因可以初步定位在proxy的toString方法上。
但是調試後發現proxy屬於$Proxy0類,而$Proxy0這個Class是運行時生成的類,網上有一個牛人貼出了$Proxy0的源碼:
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import java.lang.reflect.UndeclaredThrowableException;
- public final class $Proxy0 extends Proxy implements UserManager {
- private static Method m1;
- private static Method m0;
- private static Method m3;
- private static Method m2;
- static {
- try {
- m1 = Class.forName("java.lang.Object").getMethod("equals",
- new Class[] { Class.forName("java.lang.Object") });
- m0 = Class.forName("java.lang.Object").getMethod("hashCode",
- new Class[0]);
- m3 = Class.forName("cn.edu.jlu.proxy.UserManager").getMethod("addUser",
- new Class[0]);
- m2 = Class.forName("java.lang.Object").getMethod("toString",
- new Class[0]);
- } catch (NoSuchMethodException nosuchmethodexception) {
- throw new NoSuchMethodError(nosuchmethodexception.getMessage());
- } catch (ClassNotFoundException classnotfoundexception) {
- throw new NoClassDefFoundError(classnotfoundexception.getMessage());
- }
- }
- public $Proxy0(InvocationHandler invocationhandler) {
- super(invocationhandler);
- }
- @Override
- public final boolean equals(Object obj) {
- try {
- return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
- .booleanValue();
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- @Override
- public final int hashCode() {
- try {
- return ((Integer) super.h.invoke(this, m0, null)).intValue();
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- @Override
- public final String toString() {
- try {
- return (String) super.h.invoke(this, m2, null);
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- @Override
- public void addUser() {
- try {
- super.h.invoke(this, m3, null);
- return;
- } catch (Error e) {
- } catch (Throwable throwable) {
- throw new UndeclaredThrowableException(throwable);
- }
- }
- }
可以看到,調用toString方法的時候,調用了h的invoke方法,而h就是InvocationHandler的實例,所以是遞歸調用,所以就會出現上述所說的java.lang.StackOverflowError錯誤。
這裏順便說一下簡單編寫java動態代理的過程:
1.定義一個接口I
2.編寫該接口I的實現類Impl
3.編寫InvocationHandler接口的實現類H,構造H類對象的時候可以把要代理的對象target傳入,target完成實際的動作。在裏面的invoke方法裏編寫自己想實現的邏輯,然後再調用實際要完成的動作就可以。
4.調用Proxy.newProxyInstance方法,傳遞的三個參數分別是代理類的類加載器(可以用Impl實例的getClass().getClassLoader())
、代理類要實現的接口列表(可以用Impl實例getClass().getInterfaces())、InvocationHandler實現類的實例。
這樣就生成了$Proxy0類的對象,由於$Proxy0類實現了I接口,所以可以將對象強制轉型成I。
再說一下Proxy.newProxyInstance方法的實際過程:
1.使用傳入的InvocationHandler實例參數將Proxy類的h實例初始化,注意,如果傳入空對象的話,會拋出空指針錯誤,即h不能爲空。
2.運行時生成代理Class,即$Proxy0
3.利用上面動態生成的$Proxy0類,構造出該類的對象,並返回。
來源:http://chaisencs.iteye.com/blog/1649826