• AOPjdk动态代理的思考


    引出问题:动态代理中是谁调用了invoke方法

    为了更好的说明情况,我先写一个动态代理类

    a.Person类

    public interface Person {
        public void eating();
    
    }

    b.PersonImpl类

    public class PersonImpl implements Person{
        public void eating() {
            System.out.println("我能吃!");
        }
    }

    c.PersonProxy动态代理类

    public class PersonProxy implements InvocationHandler{
        //传入的对象
        private Object target;
        //真实对象与代理对象绑定
        public Object bind(Object target){
            this.target=target;
            //this指的是personProxy的一个实例
            Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);return proxy;
        }
        
        //invocationHandler的默认方法
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("调用代理前");
            Object object =method.invoke(target, args);
            System.out.println("调用代理后");
            return object;
        }
    
    }

    d.test类

    public class test {
        public static void main(String[] args) {
            PersonProxy proxy=new PersonProxy();
            Person person=(Person)proxy.bind(new PersonImpl());
            person.eating();
            
        }
    
    }

    e.运行结果

    调用代理前
    我能吃!
    调用代理后

    f.从以上代码和结果可以看出,我们并没有显示的调用invoke()方法,但是这个方法确实执行了。下面就整个的过程进行分析一下,

    g.我们先想一下,为什么我们在test类中只调用了代理类的bind函数,返回的代理对象就可以调用我们在实现Person类中的eating()方法?并且不是直接调用eating()方法,还在eating()的方法上添加了一些功能(输出调用代理前,调用代理后),这不就是代理的概念吗?不由的让我想起一个介绍代理的例子,火车站相当于一个实体,如果你去火车站买票,那就没啥事,如果你要去火车售票代理点买票,这个时候你就得掏点手续费,火车代理点可以给你提供一些额外的功能。扯的哪去了,说正事,从运行结果上可以看出来,当我们调用person.eating()的时候实际上调用了代理类PersonProxy中的invoke方法,但是是谁调用的呢?可以bind()函数中的newProxyInstance这个方法作为突破口,我们先来看一下Proxy类中newProxyInstance方法的源代码:

        public static Object newProxyInstance(ClassLoader loader,  
                Class<?>[] interfaces,  
                InvocationHandler h)  
        throws IllegalArgumentException  
        {  
            if (h == null) {  
                throw new NullPointerException();  
            }  
          
            /* 
             * Look up or generate the designated proxy class. 
             */  
            Class cl = getProxyClass(loader, interfaces);  
          
            /* 
             * Invoke its constructor with the designated invocation handler. 
             */  
            try {  
                   /* 
                    * private final static Class[] constructorParams = { InvocationHandler.class }; 
                    * cons即是形参为InvocationHandler类型的构造方法 
                   */  
                Constructor cons = cl.getConstructor(constructorParams);  
                return (Object) cons.newInstance(new Object[] { h });  
            } catch (NoSuchMethodException e) {  
                throw new InternalError(e.toString());  
            } catch (IllegalAccessException e) {  
                throw new InternalError(e.toString());  
            } catch (InstantiationException e) {  
                throw new InternalError(e.toString());  
            } catch (InvocationTargetException e) {  
                throw new InternalError(e.toString());  
            }  
        }  

    从源码中我们可以看到:根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类。

    h.既然newProxyInstance()返回的对象能调用eating()方法,那我们看看代理实例proxy的方法有那些?

    public class PersonProxy implements InvocationHandler{
        //传入的对象
        private Object target;
        //真实对象与代理对象绑定
        public Object bind(Object target){
            this.target=target;
            //this指的是personProxy的一个实例
            Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    //查看proxy中的方法
    for (Method name : proxy.getClass().getMethods()) { System.out.println(name); } return proxy; } //invocationHandler的默认方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用代理前"); Object object =method.invoke(target, args); System.out.println("调用代理后"); return object; } }

    运行结果:

    public final int $Proxy0.hashCode()
    public final boolean $Proxy0.equals(java.lang.Object)
    public final java.lang.String $Proxy0.toString()
    public final void $Proxy0.eating()
    public static boolean java.lang.reflect.Proxy.isProxyClass(java.lang.Class)
    public static java.lang.Object java.lang.reflect.Proxy.newProxyInstance(java.lang.ClassLoader,java.lang.Class[],java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException
    public static java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException
    public static java.lang.Class java.lang.reflect.Proxy.getProxyClass(java.lang.ClassLoader,java.lang.Class[]) throws java.lang.IllegalArgumentException
    public final void java.lang.Object.wait() throws java.lang.InterruptedException
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
    public final native java.lang.Class java.lang.Object.getClass()
    public final native void java.lang.Object.notify()
    public final native void java.lang.Object.notifyAll()
    调用代理前
    我能吃!
    调用代理后

    我们看到了方法中有eating()方法,我们试试看

    Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    ((Person) proxy).eating();

    运行结果:

    调用代理前
    我能吃!
    调用代理后
    public final int $Proxy0.hashCode()
    public final boolean $Proxy0.equals(java.lang.Object)
    public final java.lang.String $Proxy0.toString()
    public final void $Proxy0.eating()
    public static boolean java.lang.reflect.Proxy.isProxyClass(java.lang.Class)
    public static java.lang.Object java.lang.reflect.Proxy.newProxyInstance(java.lang.ClassLoader,java.lang.Class[],java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException
    public static java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException
    public static java.lang.Class java.lang.reflect.Proxy.getProxyClass(java.lang.ClassLoader,java.lang.Class[]) throws java.lang.IllegalArgumentException
    public final void java.lang.Object.wait() throws java.lang.InterruptedException
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
    public final native java.lang.Class java.lang.Object.getClass()
    public final native void java.lang.Object.notify()
    public final native void java.lang.Object.notifyAll()
    调用代理前
    我能吃!
    调用代理后

    这就说明了Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this)这句相当于在代理对象中重写了实例中的eating()方法,并且在其中调用了invoke()方法。

    i.证明是谁调用了invoke方法

    既然可以看到代理对象proxy的所有方法,我们试试代理对象的其他代理实例的方法,从h中可以看到代理方法有:hashcode(),equals(),toString(),eating()

    Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    //哈希值
    System.out.println(proxy.hashCode());

    运行结果:

    调用代理前
    调用代理后
    7486844
    调用代理前
    我能吃!
    调用代理后
    
    Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    //toString
    System.out.println(proxy.toString());

    运行结果:

    调用代理前
    调用代理后
    com.huhu.aop.PersonImpl@723d7c
    调用代理前
    我能吃!
    调用代理后

    j.反编译.class文件

        public final class $Proxy0 extends Proxy implements Person {  
            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("***.RealSubject").getMethod("request",  
                            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());  
                }  
            } //static  
          
            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);  
                }  
            }  
          
            public final void eating() {  
                try {  
                    super.h.invoke(this, m3, null);  
                    return;  
                } catch (Error e) {  
                } 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);  
                }  
            }  
        }  

    反编译的结果证明了我们h中得到的结论,顺便看到了为什么jdk动态代理只能代理接口。

  • 相关阅读:
    HOJ 2139 Spiderman's workout(动态规划)
    FZU 2107 Hua Rong Dao(dfs)
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
  • 原文地址:https://www.cnblogs.com/huhu1203/p/7520975.html
Copyright © 2020-2023  润新知