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

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

a.Person类

  1. public interface Person {
  2. public void eating();
  3.  
  4. }

b.PersonImpl类

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

c.PersonProxy动态代理类

  1. public class PersonProxy implements InvocationHandler{
  2. //传入的对象
  3. private Object target;
  4. //真实对象与代理对象绑定
  5. public Object bind(Object target){
  6. this.target=target;
  7. //this指的是personProxy的一个实例
  8. Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);return proxy;
  9. }
  10.  
  11. //invocationHandler的默认方法
  12. public Object invoke(Object proxy, Method method, Object[] args)
  13. throws Throwable {
  14. System.out.println("调用代理前");
  15. Object object =method.invoke(target, args);
  16. System.out.println("调用代理后");
  17. return object;
  18. }
  19.  
  20. }

d.test类

  1. public class test {
  2. public static void main(String[] args) {
  3. PersonProxy proxy=new PersonProxy();
  4. Person person=(Person)proxy.bind(new PersonImpl());
  5. person.eating();
  6.  
  7. }
  8.  
  9. }

e.运行结果

  1. 调用代理前
  2. 我能吃!
  3. 调用代理后

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

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

  1. public static Object newProxyInstance(ClassLoader loader,
  2. Class<?>[] interfaces,
  3. InvocationHandler h)
  4. throws IllegalArgumentException
  5. {
  6. if (h == null) {
  7. throw new NullPointerException();
  8. }
  9.  
  10. /*
  11. * Look up or generate the designated proxy class.
  12. */
  13. Class cl = getProxyClass(loader, interfaces);
  14.  
  15. /*
  16. * Invoke its constructor with the designated invocation handler.
  17. */
  18. try {
  19. /*
  20. * private final static Class[] constructorParams = { InvocationHandler.class };
  21. * cons即是形参为InvocationHandler类型的构造方法
  22. */
  23. Constructor cons = cl.getConstructor(constructorParams);
  24. return (Object) cons.newInstance(new Object[] { h });
  25. } catch (NoSuchMethodException e) {
  26. throw new InternalError(e.toString());
  27. } catch (IllegalAccessException e) {
  28. throw new InternalError(e.toString());
  29. } catch (InstantiationException e) {
  30. throw new InternalError(e.toString());
  31. } catch (InvocationTargetException e) {
  32. throw new InternalError(e.toString());
  33. }
  34. }

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

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

  1. public class PersonProxy implements InvocationHandler{
  2. //传入的对象
  3. private Object target;
  4. //真实对象与代理对象绑定
  5. public Object bind(Object target){
  6. this.target=target;
  7. //this指的是personProxy的一个实例
  8. Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    //查看proxy中的方法
  9. for (Method name : proxy.getClass().getMethods()) {
  10. System.out.println(name);
  11. }
  12. return proxy;
  13. }
  14.  
  15. //invocationHandler的默认方法
  16. public Object invoke(Object proxy, Method method, Object[] args)
  17. throws Throwable {
  18. System.out.println("调用代理前");
  19. Object object =method.invoke(target, args);
  20. System.out.println("调用代理后");
  21. return object;
  22. }
  23.  
  24. }

运行结果:

  1. public final int $Proxy0.hashCode()
  2. public final boolean $Proxy0.equals(java.lang.Object)
  3. public final java.lang.String $Proxy0.toString()
  4. public final void $Proxy0.eating()
  5. public static boolean java.lang.reflect.Proxy.isProxyClass(java.lang.Class)
  6. public static java.lang.Object java.lang.reflect.Proxy.newProxyInstance(java.lang.ClassLoader,java.lang.Class[],java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException
  7. public static java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException
  8. public static java.lang.Class java.lang.reflect.Proxy.getProxyClass(java.lang.ClassLoader,java.lang.Class[]) throws java.lang.IllegalArgumentException
  9. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  10. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  11. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  12. public final native java.lang.Class java.lang.Object.getClass()
  13. public final native void java.lang.Object.notify()
  14. public final native void java.lang.Object.notifyAll()
  15. 调用代理前
  16. 我能吃!
  17. 调用代理后

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

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

运行结果:

  1. 调用代理前
  2. 我能吃!
  3. 调用代理后
  4. public final int $Proxy0.hashCode()
  5. public final boolean $Proxy0.equals(java.lang.Object)
  6. public final java.lang.String $Proxy0.toString()
  7. public final void $Proxy0.eating()
  8. public static boolean java.lang.reflect.Proxy.isProxyClass(java.lang.Class)
  9. public static java.lang.Object java.lang.reflect.Proxy.newProxyInstance(java.lang.ClassLoader,java.lang.Class[],java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException
  10. public static java.lang.reflect.InvocationHandler java.lang.reflect.Proxy.getInvocationHandler(java.lang.Object) throws java.lang.IllegalArgumentException
  11. public static java.lang.Class java.lang.reflect.Proxy.getProxyClass(java.lang.ClassLoader,java.lang.Class[]) throws java.lang.IllegalArgumentException
  12. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  13. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  14. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  15. public final native java.lang.Class java.lang.Object.getClass()
  16. public final native void java.lang.Object.notify()
  17. public final native void java.lang.Object.notifyAll()
  18. 调用代理前
  19. 我能吃!
  20. 调用代理后

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

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

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

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

运行结果:

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

运行结果:

  1. 调用代理前
  2. 调用代理后
  3. com.huhu.aop.PersonImpl@723d7c
  4. 调用代理前
  5. 我能吃!
  6. 调用代理后

j.反编译.class文件

  1. public final class $Proxy0 extends Proxy implements Person {
  2. private static Method m1;
  3. private static Method m0;
  4. private static Method m3;
  5. private static Method m2;
  6.  
  7. static {
  8. try {
  9. m1 = Class.forName("java.lang.Object").getMethod("equals",
  10. new Class[] { Class.forName("java.lang.Object") });
  11.  
  12. m0 = Class.forName("java.lang.Object").getMethod("hashCode",
  13. new Class[0]);
  14.  
  15. m3 = Class.forName("***.RealSubject").getMethod("request",
  16. new Class[0]);
  17.  
  18. m2 = Class.forName("java.lang.Object").getMethod("toString",
  19. new Class[0]);
  20.  
  21. } catch (NoSuchMethodException nosuchmethodexception) {
  22. throw new NoSuchMethodError(nosuchmethodexception.getMessage());
  23. } catch (ClassNotFoundException classnotfoundexception) {
  24. throw new NoClassDefFoundError(classnotfoundexception.getMessage());
  25. }
  26. } //static
  27.  
  28. public $Proxy0(InvocationHandler invocationhandler) {
  29. super(invocationhandler);
  30. }
  31.  
  32. @Override
  33. public final boolean equals(Object obj) {
  34. try {
  35. return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
  36. } catch (Throwable throwable) {
  37. throw new UndeclaredThrowableException(throwable);
  38. }
  39. }
  40.  
  41. @Override
  42. public final int hashCode() {
  43. try {
  44. return ((Integer) super.h.invoke(this, m0, null)).intValue();
  45. } catch (Throwable throwable) {
  46. throw new UndeclaredThrowableException(throwable);
  47. }
  48. }
  49.  
  50. public final void eating() {
  51. try {
  52. super.h.invoke(this, m3, null);
  53. return;
  54. } catch (Error e) {
  55. } catch (Throwable throwable) {
  56. throw new UndeclaredThrowableException(throwable);
  57. }
  58. }
  59.  
  60. @Override
  61. public final String toString() {
  62. try {
  63. return (String) super.h.invoke(this, m2, null);
  64. } catch (Throwable throwable) {
  65. throw new UndeclaredThrowableException(throwable);
  66. }
  67. }
  68. }

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

AOP---jdk动态代理的思考的更多相关文章

  1. AOP jdk动态代理

    一: jdk动态代理是Spring AOP默认的代理方法.要求 被代理类要实现接口,只有接口里的方法才能被代理,主要步骤是先创建接口,接口里创建要被代理的方法,然后定义一个实现类实现该接口,接着将被代 ...

  2. Spring AOP --JDK动态代理方式

    我们知道Spring是通过JDK或者CGLib实现动态代理的,今天我们讨论一下JDK实现动态代理的原理. 一.简述 Spring在解析Bean的定义之后会将Bean的定义生成一个BeanDefinit ...

  3. Spring AOP JDK动态代理与CGLib动态代理区别

    静态代理与动态代理 静态代理 代理模式 (1)代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. (2)静态代理由 业务实现类.业务代理类 两部分 ...

  4. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  5. Spring AOP详解 、 JDK动态代理、CGLib动态代理

    AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...

  6. jdk动态代理与cglib代理、spring aop代理实现原理

    原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...

  7. jdk动态代理与cglib代理、spring aop代理实现原理解析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  8. 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  9. Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程

    spring-aop-4.3.7.RELEASE  在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...

  10. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

随机推荐

  1. mybatis if-else(写法)

    mybaits 中没有else要用chose when otherwise 代替 范例一 <!--批量插入用户--> <insert id="insertBusinessU ...

  2. navicat创建存储过程、触发器和使用游标

    创建存储过程和触发器 1.建表 首先先建两张表(users表和number表),具体设计如下图: 2.存储过程 写一个存储过程,往users表中插入数据,创建过程如下: 代码如下: BEGIN #Ro ...

  3. MySQL学习(二)复制

        复制解决的问题是保持多个服务器之间的数据的一致性,就如同通过复制保持两个文件的一致性一样,只不过MySQL的复制要相对要复杂一些,其基本过程如下:     1)在主库上将数据更改记录到二进制日 ...

  4. 【MySQL】数据库字段类型

    1.数值型 整型 TINYINT SMALLINT MEDIUMINT INT BIGINT 浮点型 FLOAT(m,n) - m表示总位数,n表示小数位数. DOUBLE(m,n) DECIMAL( ...

  5. asp.net mvc 下拉列表

    第一步:新建一个格式化下拉列表的公共类文件 using System; using System.Collections; using System.Collections.Generic; usin ...

  6. 前端模块化:RequireJS(转)

    前言 前端模块化能解决什么问题? 模块的版本管理 提高可维护性 -- 通过模块化,可以让每个文件职责单一,非常有利于代码的维护 按需加载 -- 提高显示效率 更好的依赖处理 -- 传统的开发模式,如果 ...

  7. iOS 环信透传cmd消息多次重复接收,解决办法

    由于项目需求,需要在项目中接到消息的时候做不同界面的不同的操作,哪儿需要哪儿就要添加代理:引起代理事件重复执行:所以要在VC显示的时候添加代理,消失的时候删除代理 环信 透传 消息多次接收情况(由于代 ...

  8. Linux权限分析

    我看过网上的一些有关Linux的权限分析,有些说的不够清楚,另外一些说的又太复杂.这里我尽量简单.清楚的把Linux权限问题阐述明白,Linux权限没有那么复杂. Linux权限问题要区分文件权限和目 ...

  9. React:入门计数器

    ---恢复内容开始--- 把React的官网入门例子全看一遍,理解了,但自己从头开始写有点困难,这次强迫自己从头开始写,并写好注释: import React, { Component } from ...

  10. HTML篇(下·)

    13.Label的作用是什么?是怎么用的? label标签来定义表单控制间的关系,当用户选择该标签时,浏览器会自动将焦点转到和标签相关的表单事件上. <label for="Name& ...