最近用到了java的动态代理,虽然会用,但不了解他具体是怎么实现,抽空看看了看他的源码。

说到Java的动态代理就不能不说到代理模式,动态代理也就是多了一个’动态’两字,在《大话设计模式》中不是有这句话吗?“反射,反射程序员的快乐”,这里也不例外,他在底层也是使用了反射来创建对象。

一、 为了让我们更加明白的了解动态代理,我们先来复习一下代理模式吧(没有学过的,也得假装复习是复习呀,不然掉面)。

public interface BookManager {void addBook();
}

  

 1 package com.test;
 2
 3 public class Library implements BookManager {
 4
 5     public void addBook() {
 6         // TODO Auto-generated method stub
 7         System.out.println("增加图书。。。。。");
 8     }
 9
10 }

 1 package com.test;
 2
 3 public class Agent implements BookManager {
 4     private BookManager library;
 5
 6     public BookManager getLibrary() {
 7         return library;
 8     }
 9
10     public void setLibrary(BookManager library) {
11         this.library = library;
12     }
13
14     public void addBook() {
15         // TODO Auto-generated method stub
16         System.out.println("添加图书之前");
17         library.addBook();
18         System.out.println("添加图书之后");
19     }
20
21 }

测试代码

package com.test;public class BookTest {public static void main(String[] args) {BookManager library = new Library();Agent agent =  new Agent();agent.setLibrary(library);agent.addBook();}
}执行结果为
添加图书之前
增加图书。。。。。
添加图书之后

从这里可以看到在代理模式中要求是都实现了相同的接口,所以这样的代码,移植性不强,所以催生出动态代理。动态代理不要求,必须实现相同的接口,减少了代码量。

先上代码

public interface BookFacade {public void addBook();
}

  

public class BookFacadeImpl implements BookFacade,system {public void addBook() {// TODO Auto-generated method stubSystem.out.println("增加图书方法。。。");  }public void doSys() {// TODO Auto-generated method stubSystem.out.println("dsfsdfsd");}}

  

public class BookFacadeProxy implements InvocationHandler {private Object target;  /** * 绑定委托对象并返回一个代理类 * @param target * @return */  public Object bind(Object target) {  this.target = target;  //取得代理对象  return Proxy.newProxyInstance(target.getClass().getClassLoader(),  target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  }  public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable {  Object result=null;  System.out.println("事物开始");  //执行方法  System.out.println("ClassLoad"+proxy.getClass().getSimpleName());result=method.invoke(target, args);  System.out.println("事物结束");  return result;  }
}

  

public class TestProxy {public static void main(String[] args) {BookFacadeProxy proxy = new BookFacadeProxy();  BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  bookProxy.addBook(); ProxyGeneratorUtils.writeProxyClassToHardDisk("F:/$Proxy11.class");}
}

  我先声明后面这段代码我盗用了其他网友的成果。

先说明用法,再来解释为什么会是这样的呢?

第一步 你必须得声明一个接口,而且在目标类必须实现这个接口,不然你使用动态代理是不会成功的。

第二步 需要实现 InvocationHandler 接口,创建一个代理类,这个代理类里需要重写invoke方法,在这个方法里,需要写上多被代理对象的调用method.invoke(target, args),如果不知道method.invoke()是做什么用的,可以去看看反射就明白了。参数有两个一个是被代理的对象,第二个就是调用该方法的参数

第三步 需要获得代理对象,可以通过Object Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

方法来生成一个代理对象。

具体的第一个是使用那一个类加载器加载,第二个就是需要绑定的接口,第三个就是持有处理的对象。

测试方法安装你正常调用相应的方法就行。

测试类执行结果如下

事物开始
增加图书方法。。。
事物结束

现在我们知道用法了,按照我们一般考虑问题的思路是,

生成的代理对象,能调用接口的的方法,肯定是实现了接口这是我们的猜想一,这个涉及到代理对象的生成。

第二个调用addBook方法,能执行,invoke方法,他是怎么调用的呢。

那么我们现在就进入源码吧,先来看看对象是怎么生成的。

Returns an instance of a proxy class for the specified interfacesthat dispatches method invocations to the specified invocationhandler.看看注释就明白了,返回一个代理类的对象,而且还是实现了你进来接口的类public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{if (h == null) {throw new NullPointerException();}/** 生成一个代理类*/Class<?> cl = getProxyClass(loader, interfaces);/** 通过反射用构造方法生成一个对象*/try {Constructor cons = cl.getConstructor(constructorParams);return 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());}}

  上面大家可以看到,生成了一个对象返回去了,这个对象就是我们所说的代理对象,那么我们可以看看这个class 是怎么生成?

public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces)throws IllegalArgumentException{验证接口的长度if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}这个class 对象就是我们被返回对象的定义Class<?> proxyClass = null;/* collect interface names to use as key for proxy class cache */String[] interfaceNames = new String[interfaces.length];// for detecting duplicatesSet<Class<?>> interfaceSet = new HashSet<>();for (int i = 0; i < interfaces.length; i++) {String interfaceName = interfaces[i].getName();Class<?> interfaceClass = null;try {interfaceClass = Class.forName(interfaceName, false, loader);} catch (ClassNotFoundException e) {}if (interfaceClass != interfaces[i]) {throw new IllegalArgumentException(interfaces[i] + " is not visible from class loader");}/** Verify that the Class object actually represents an* interface.*/if (!interfaceClass.isInterface()) {throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");}/** Verify that this interface is not a duplicate.*/if (interfaceSet.contains(interfaceClass)) {throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());}interfaceSet.add(interfaceClass);interfaceNames[i] = interfaceName;}....... 中间省略N多                       生成一个代理class文件,这个就是我们要被返回的class 对象/** Generate the specified proxy class.*/byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);try {proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);} catch (ClassFormatError e) {/*

  这样我们就知道这个代理对象是怎么生成的。

接下来我们第2个问题就是这个invoke 方法是什么时候调用的。

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);

  从这个方法我们可以看出来,他可以生成一个二进制的文件,那么我们把这个文件写到本地就可以看到这个文件了。

public final class $Proxy110 extends Proxyimplements BookFacade
{private static Method m1;private static Method m3;private static Method m0;private static Method m2;public $Proxy110(InvocationHandler paramInvocationHandler)throws {super(paramInvocationHandler);}public final boolean equals(Object paramObject)throws {try{return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}public final void addBook()throws {try{this.h.invoke(this, m3, null);return;}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}

  这个是生成

转载于:https://www.cnblogs.com/2014----/p/4050886.html

jdk动态代理源码学习相关推荐

  1. jdk动态代理源码分析(一)---代理的定义

    最近在看rpc的实现原理,发现大部分通用的rpc框架在实现远程调用的时候,都是通过java动态代理封装好了通信细节,让用户可以像调用本地服务一样调用远程服务.但是关于java动态代理有两个问题想不通: ...

  2. 深入剖析JDK动态代理源码实现

    动态代理.静态代理优缺点 优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性.这是代理的共有优点.动态代理只有在用到被代理对象的时候才会对被代理类进行类加载. 而静态代理在编译器就已经开始占内存 ...

  3. JDK动态代理源码解析

    分析版本jdk1.8 在分析jdk动态代理之前,先来了解java WeakReference弱引用的使用.运行期创建目标对象的代理非常耗时,使用缓存来存储生成的代理类显得尤为重要.jdk动态代理使用弱 ...

  4. 动态代理及JDK动态代理源码分析

    1.为什么要动态代理 现在有这样一个需求:在聊天系统中,把每一个所说的话记录到日志文件里面,初学者可能是这样来设计 在speak方法中调用log方法,记录到数据库.这样设计有明显的不足:1.log方法 ...

  5. Java动态代理源码详解

    一.概述   前言:本文除了讲解JDK动态代理及CGLIB动态代理实例和应用外,还会讲解JDK动态代理源码实现过程以及自己写一手个JDK动态代理等.   动态代理在很多底层框架中都会用得到,比如在Sp ...

  6. javabean反射改字段内容_BAT程序员编写:深入理解 Java 反射和动态代理源码分析...

    什么是反射 反射(Reflection)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. 通过反射机制,可以在运行时访问 Java ...

  7. 动态代理源码分析,实现自己的动态代理

    什么是代理 增强一个对象的功能 买火车票,app就是一个代理,他代理了火车站,小区当中的代售窗口 java当中如何实现代理 java实现的代理的两种办法 代理的名词 代理对象 增强后的对象 目标对象 ...

  8. Android动态代理源码分析

    前言 前面我们简单介绍了代理模式的使用Android设计模式详解之代理模式,我们也明白了动态代理模式的重要性,那动态代理究竟是如何实现将方法交给InvocationHandler.invoke执行的呢 ...

  9. jkd动态代理源码分析

    代理对象的生成方法是: Proxy.newProxyInstance(...),进入这个方法内部,一步一步往下走会发现会调用 ProxyGenerator.generateProxyClass(),这 ...

最新文章

  1. MySQL 为什么表的数据删除一般,表文件大小不变?
  2. kafka的SASL的适用业务场景
  3. android rxbus 一个页面监听,Android RxBus的使用
  4. 配置源码管理工具(2)
  5. 前端学习(1716):前端系列javascript之页面配置下
  6. node 安装 webpack
  7. rocketmq存储结构_阿里专家分享内部绝密RocketMQ核心原理与最佳实践笔记
  8. Python基础(map/reduce)
  9. @程序员,一文掌握 Web 应用中的图片优化技巧!
  10. python识别复杂验证码2020_Python识别验证码!学会这步,百分之60的网站你基本都能识别了!...
  11. 开课吧Java课堂:特殊的字符串如何操作,字符串如何连接
  12. 朋友们给《Java程序员,上班那点事儿》的赠言
  13. 部分贴片电阻标准阻值表(印字阻值对照)
  14. 自检zabbix健康脚本
  15. React TypeScript react+ts 包下载
  16. 资源管理Placement部署(Nova)
  17. 【英语】maintext2-Emotional Mastery译文
  18. Min3D测试-在Android里面载入MMD模型-快速3D模型显示测试-By黑月君
  19. MAC 常见的终端指令
  20. HTML添加css文件和js文件

热门文章

  1. 以太坊:比特币 + 无限可能
  2. sql avg函数使用格式_SQL AVG-SQL平均函数用语法示例解释
  3. 让我们讨论一下变量,以及为什么要在JavaScript中使用它们。
  4. Apache服务器部署(2)
  5. 什么是python第三方库
  6. .net内存回收与Dispose﹐Close﹐Finalize方法
  7. 使用Novell.Directory.Ldap.NETStandard在.NET Core中验证AD域账号
  8. 统一客服消息返回错误:{errcode:43004,errmsg:require subscribe hint: [9Vv08633952]}
  9. 《从零开始学Swift》学习笔记(Day 47)——final关键字
  10. openresty 前端开发入门五之Mysql篇