JDK动态代理之代理对象与目标对象

问题的引出

下述所有类均定义在包structure.proxy.dynamicproxy中。

  • 定义一个接口AbstractUserDAO
public interface AbstractUserDAO {
    Boolean findUserById(String userId);
}
  • 定义一个接口AbstractUserDAO的实现类UserDAO
public class UserDAO implements AbstractUserDAO {
    @Override
    public Boolean findUserById(String userId) {
        System.out.println("findUserById" + userId);
        return true;
    }
}
  • 定义一个接口InvocationHandler的实现类DAOLogHandler
public class DAOLogHandler implements InvocationHandler {
    private Object object;

    public DAOLogHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("findUserById")) {
            System.out.println("before invoke");
        }
        Object result = method.invoke(object, args);
        if (method.getName().equals("findUserById")) {
            System.out.println("after invoke");
        }
        return result;
    }
}
  • 定义测试类Test
public class Test {
    public static void main(String[] args) {
        AbstractUserDAO userDAO = new UserDAO();
        InvocationHandler handler = new DAOLogHandler(userDAO);
        AbstractUserDAO proxy = (AbstractUserDAO) Proxy.newProxyInstance(AbstractUserDAO.class.getClassLoader(),
                new Class[] {AbstractUserDAO.class}, handler);
        System.out.println(Objects.equals(userDAO, proxy));
        System.out.println("userDAO = " + userDAO);
        System.out.println("proxy = " + proxy);
        System.out.println("userDAO.getClass() = " + userDAO.getClass());
        System.out.println("proxy.getClass() = " + proxy.getClass());
        System.out.println("userDAO.hashCode() = " + userDAO.hashCode());
        System.out.println("proxy.hashCode() = " + proxy.hashCode());
    }
}
  • 测试结果
false
userDAO = structure.proxy.dynamicproxy.UserDAO@2b193f2d
proxy = structure.proxy.dynamicproxy.UserDAO@2b193f2d
userDAO.getClass() = class structure.proxy.dynamicproxy.UserDAO
proxy.getClass() = class com.sun.proxy.$Proxy0
userDAO.hashCode() = 723074861
proxy.hashCode() = 723074861
  • 结果分析
    首先下一个结论,代理对象proxy和目标对象userDAO并不是同一个对象,但是它们的hashCode()方法和toString()方法的结果均相同,这是因为JDK动态代理只对接口中声明的方法进行代理,hashCode()方法和toString()方法是在Object中定义的,不会被代理对象拦截。
    getClass()方法返回的是对象的运行时类型信息,可以看到,代理对象proxy的类型是class com.sun.proxy.$Proxy0,而目标对象userDAO的类型是structure.proxy.dynamicproxy.UserDAO

为什么JDK动态代理只能对接口中的方法进行代理呢?

  • 修改上述代码中的测试类Test,使其输出动态代理生成的.class文件
public class Test {
    public static void main(String[] args) throws IOException {
        AbstractUserDAO userDAO = new UserDAO();
        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{userDAO.getClass()});
        FileOutputStream os = new FileOutputStream("Proxy0.class");
        os.write(bytes);
        os.close();
    }
}
  • 反编译Proxy0.class文件
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import structure.proxy.dynamicproxy.UserDAO;

public final class $Proxy0 extends Proxy implements UserDAO {
    private static Method m1;
    private static Method m8;
    private static Method m2;
    private static Method m5;
    private static Method m3;
    private static Method m4;
    private static Method m7;
    private static Method m9;
    private static Method m0;
    private static Method m6;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void notify() throws  {
        try {
            super.h.invoke(this, m8, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait(long var1) throws InterruptedException {
        try {
            super.h.invoke(this, m5, new Object[]{var1});
        } catch (RuntimeException | InterruptedException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final Boolean findUserById(String var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void wait(long var1, int var3) throws InterruptedException {
        try {
            super.h.invoke(this, m4, new Object[]{var1, var3});
        } catch (RuntimeException | InterruptedException | Error var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new UndeclaredThrowableException(var6);
        }
    }

    public final Class getClass() throws  {
        try {
            return (Class)super.h.invoke(this, m7, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void notifyAll() throws  {
        try {
            super.h.invoke(this, m9, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait() throws InterruptedException {
        try {
            super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | InterruptedException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m8 = Class.forName("structure.proxy.dynamicproxy.UserDAO").getMethod("notify");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m5 = Class.forName("structure.proxy.dynamicproxy.UserDAO").getMethod("wait", Long.TYPE);
            m3 = Class.forName("structure.proxy.dynamicproxy.UserDAO").getMethod("findUserById", Class.forName("java.lang.String"));
            m4 = Class.forName("structure.proxy.dynamicproxy.UserDAO").getMethod("wait", Long.TYPE, Integer.TYPE);
            m7 = Class.forName("structure.proxy.dynamicproxy.UserDAO").getMethod("getClass");
            m9 = Class.forName("structure.proxy.dynamicproxy.UserDAO").getMethod("notifyAll");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m6 = Class.forName("structure.proxy.dynamicproxy.UserDAO").getMethod("wait");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

上述代码中可以看到$Proxy0已经继承了Proxy类,由于Java只允许单继承,故只能对接口进行动态代理。

你可能感兴趣的:(JAVA,ABC)