InvocationHandle的invoke方法[通俗易懂]

InvocationHandle的invoke方法[通俗易懂]在学习代理模式中接触到了动态代理的相关内容,这是AOP的核心内容。先用一个例子说明动态代理的使用//接口(动态代理只能代理接口)publicinterfaceSubject{publicvoidrequest();}//接口实现:实现了Subject的request()方法publicclassRealSubjecti

大家好,又见面了,我是你们的朋友全栈君。

在学习代理模式中接触到了动态代理的相关内容,这是AOP的核心内容。先用一个例子说明 动态代理 的使用

//接口(动态代理只能代理接口)  
public interface Subject {  
      
    public void request();  
}  

//接口实现 :实现了Subject的request()方法  
public class RealSubject implements Subject{  
      
    public void request(){  
        System.out.println("From real subject.");  
    }  
} 

Inb

//实现了InvocationHandler  接口
public class DynamicSubject implements InvocationHandler  
{  
    private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象  
  
    public DynamicSubject()  
    {  
    }  
  
    public DynamicSubject(Object obj)  
    {  
        this.obj = obj;  
    }  
  
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
    {  
        System.out.println("before calling " + method);  
  
        method.invoke(obj, args);  
  
        System.out.println("after calling " + method);  
  
        return null;  
    }  
  
}  
public class Client {  
  
    public static void main(String[] args) throws Throwable{  
        // TODO Auto-generated method stub  
  
        Subject rs=new RealSubject();//这里指定被代理类  
        InvocationHandler ds=new DynamicSubject(rs);  
        Class<?> cls=rs.getClass();  
          
        //生成代理类  ,注意subject是Proxy的子类并且实现了Subject接口的一个类。
          
        Subject subject=(Subject) Proxy.newProxyInstance(  
                cls.getClassLoader(),cls.getInterfaces(), ds);       

}


以上就是动态代理的使用方法,有一点很奇怪,那就是invoke方法是如何被调用的呢? 可以看到在以上代码中并没有invoke的身影,那是因为有关invoke的调用时在Proxy类中,invoke方法并不是给我们显示的调用,查看源码我们可以看到。  

首先看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 {  
           /* 
            * Proxy源码开始有这样的定义: 
            * 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());  
    }  
}  

这个方法实际是利用反射,返回了一个Proxy的子类,实现了指定的接口,返回的类叫做$Proxy0, 这个类包含了invoke的秘密! 请看源码:

public final class $Proxy0 extends Proxy implements Subject {  
    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 request() {  
        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);  
        }  
    }  
}

该类中利用反射获取到了4个方法,Object类自带的equals,hasCode,toString ,以及接口Subject的唯一方法request,因此当我们在主函数中调用request.xxx(方法名),就是在$Proxy0类中调用相应方法,每个方法中都有 super.h.invoke(this,m3,null);        invoke函数在此起到了作用!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/138722.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • csdn自动签到python脚本

    csdn自动签到python脚本

    2021年10月3日
    47
  • Nginx(二)——nginx.conf 配置文件

    Nginx(二)——nginx.conf 配置文件

    2021年6月12日
    163
  • zookeeper入门教程_ZooKeeper的事件机制原理

    zookeeper入门教程_ZooKeeper的事件机制原理zookeeperwatcher架构zookeeper 配置中心分布式ID分布式锁集群搭建数据一致性协议:zab协议Zookeeper Leader选举Observer角色及其配置watcher架构客户端首先将Watcher注册到服务器,同时将Watch对象保存到客户端的Watch管理器中。当Zookeeper服务器监听到的数据发生变化时,服务器会通知客户端,接着客户端的Watch管理器会触发相关的Watcher来回调响应处理逻辑,从而完成整体的数据发布/订阅流程。javaAPIJava

    2022年8月9日
    3
  • setfacl解释「建议收藏」

    setfacl解释「建议收藏」setfacl:设置文件访问控制列表,针对单独文件,设置单独用户权限用法:setfacl-参数用户权限文件参数:-m,–modify=acl更改文件的访问控制列表-M,–modify-file=file从文件读取访问控制列表条目更改-x,–remove=acl根据文件中访问控制列表移除条目-X,–remove-file=file从文件读取访问控制列表条目…

    2022年6月16日
    25
  • java dom4j解析_java dom4j解析器使用

    java dom4j解析_java dom4j解析器使用JavaDOM4J解析器介绍DOM4J是一个开源的,基于Java的库来解析XML文档,它具有高度的灵活性,高性能和内存效率的API。这是java的优化,使用Java集合像列表和数组。它可以使用DOM,SAX,XPath和XSLT。它解析大型XML文档时具有极低的内存占用。优点DOM4J使Java开发的灵活性和XML解析代码易于维护。它是轻量级的,快速的API。DOM4J类DOM4J定义了几个J…

    2022年7月26日
    4
  • 2021-07-08总结

    2021-07-08总结

    2022年2月19日
    29

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号