一、JDK动态代理实现案例

Person接口

package com.zhoucong.proxy.jdk;

public interface Person {

//    寻找真爱
void findlove(); }

人物实现类

package com.zhoucong.proxy.jdk;

public class Zhangsan implements Person{

    @Override
public void findlove() {
System.out.println("我叫张三,性别女,我找对象的要求如下:\n");
System.out.println("高富帅");
System.out.println("有房有车");
System.out.println("身高180cm以上,体重70kg");
} }

代理类

package com.zhoucong.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class MeiPo implements InvocationHandler{ private Person target; // 获取被代理人的个人资料
public Object getInstance(Person target) throws Exception {
this.target = target;
Class clazz = target.getClass();
System.out.println("被代理对象的class是:"+ clazz);
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); } @Override
public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆!!");
System.out.println("开始信息海选...");
System.out.println("-------------"); method.invoke(this.target, args);
System.out.println("-------------");
System.out.println("如果合适的话,就准备办事");
return null;
} }

运行测试

package com.zhoucong.proxy.jdk;
public class TestFindLove { public static void main(String[] args) { try {
Person obj = (Person) new MeiPo().getInstance(new Zhangsan());
System.out.println(obj.getClass());
obj.findlove(); /**
* 原理:
* 1.拿到被代理对象的引用,然后获取它的接口
* 2.jdk代理重新生成一个类,同时实现我们个额的代理对象所实现的接口
* 3.把被代理对象的引用也拿到了
* 4.重新动态生成一个class字节码
* 5.然后编译
*/ } catch (Exception e) {
e.printStackTrace();
}
} }

运行结果:

重点:

代理前对象为  com.zhoucong.proxy.jdk.Zhangsan

代理后获得的对象  com.sun.proxy.$Proxy0

二、原理分析

获取$Proxy0.class字节码内容

package com.zhoucong.proxy.jdk;

import java.io.FileOutputStream;
import sun.misc.ProxyGenerator; public class TestFindLove { public static void main(String[] args) { try {
Person obj = (Person) new MeiPo().getInstance(new Zhangsan());
System.out.println(obj.getClass());
obj.findlove(); // 获取字节码内容
// ProxyGenerator需要导入jdk安装目录jre/bin下的rt.jar byte[] generateProxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class[] { Person.class });
// 输出到本地
FileOutputStream os = new FileOutputStream("E:/GP_WORKSPACE/$Proxy0.class");
os.write(generateProxyClass);
os.close(); } catch (Exception e) {
e.printStackTrace();
}
} }

利用反编译工具得到Java文件如下:

$Proxy0.java

import com.zhoucong.proxy.jdk.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Person {
private static Method m1; private static Method m2; private static Method m0; private static Method m3; public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
} public final boolean equals(Object paramObject) {
try {
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
} public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
} public final int hashCode() {
try {
return ((Integer)this.h.invoke(this, m0, null)).intValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
} public final void findlove() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
} static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("com.zhoucong.proxy.jdk.Person").getMethod("findlove", new Class[0]);
return;
} catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}

要点分析:

特点:1、JDK代理生成的类实现了Person接口继承父类Proxy

    分析:JDK实现动态代理必须要有接口(cglib没有)

   2、静态代码块获取了接口中的方法

m3 = Class.forName("com.zhoucong.proxy.jdk.Person").getMethod("findlove", new Class[0]);

   3、JDK代理生成的类实现了接口方法,里面写了重要的一句话

 this.h.invoke(this, m3, null);

分析:this.h 去父类Proxy中查看得知为父类的成员变量

/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;

即MeiPo类并且调用了里面的Object invoke(Object arg0, Method method, Object[] args)方法

 @Override
public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆!!");
System.out.println("开始信息海选...");
System.out.println("-------------");
// this.target.findlove(); //还可以写成如下,效果一样
  // 利用反射机制实现
method.invoke(this.target, args);
System.out.println("-------------");
System.out.println("如果合适的话,就准备办事");
return null;
}

三、手写实现JDK动态代理

JDK动态代理案例与原理分析的更多相关文章

  1. (转)细说JDK动态代理的实现原理

    原文:http://blog.csdn.net/mhmyqn/article/details/48474815 关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spr ...

  2. JDK动态代理实现源码分析

    JDK动态代理实现方式 在Spring框架中经典的AOP就是通过动态代理来实现的,Spring分别采用了JDK的动态代理和Cglib动态代理,本文就来分析一下JDK是如何实现动态代理的. 在分析源码之 ...

  3. JDK动态代理的实现原理

    学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504

  4. jdk动态代理使用及原理

    jdk动态代理的使用 1.创建实现InvocationHandler接口的类,实现invoke(Object proxy, Method method, Object[] args)接口,其中invo ...

  5. Java JDK 动态代理实现和代码分析

    JDK 动态代理 内容 一.动态代理解析 1. 代理模式 2. 为什么要使用动态代理 3. JDK 动态代理简单结构图 4. JDK 动态代理实现步骤 5. JDK 动态代理 API 5.1 java ...

  6. JDK 动态代理 源码简单分析

    代理的作用就是在访问真实对象之前或者之后可以额外加入一些操作. JDK  的动态代理 只需要 5 步. 真实对象必须要实现接口,首先创建一个接口 public interface HelloWorld ...

  7. jdk动态代理 案例

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflec ...

  8. 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)

    代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...

  9. 解析JDK动态代理实现原理

    JDK动态代理使用实例 代理模式的类图如上.关于静态代理的示例网上有很多,在这里就不讲了. 因为本篇讲述要点是JDK动态代理的实现原理,直接从JDK动态代理实例开始. 首先是Subject接口类. p ...

随机推荐

  1. APP非功能测试

    1.移动APP启动时间测试 问题:如何获取启动时间? 答:通过adb的logcat来获取Activity启动时间.用户体验时间=Activity启动时间+启动中异步UI绘制的时间. 启动时间的测试主要 ...

  2. Geoserver对发布的数据源进行金字塔切片

    一.建立切片数据源 1.1建立工作区 1.2添加数据 我这里是老师给的高清卫星地图数据,格式为tif 工作区选择之前建立的工作区,浏览那里选择对应的文件 1.3建立切片源的图层 这里建立的图层中先不用 ...

  3. 如何设置10px

    chrome浏览器小于12px字体默认显示12px? font-size:10px: -webkit-transform:scal(0.83):

  4. Codeforces Edu Round 52 A-E

    A. Vasya and Chocolate 模拟题.数据会爆\(int\),要开\(long\) \(long\) #include <iostream> #include <cs ...

  5. 谷歌浏览器debugger技巧

    1.Pause/Resume script execution:暂停/恢复脚本执行(程序执行到下一断点停止). 2.Step over next function call:逐步执行. 跳过按钮.它会 ...

  6. JavaScript:浏览器的本地存储

    cookie.localStorage.sessionStorage的使用 <!DOCTYPE html> <html lang="en"> <hea ...

  7. Jmeter(7)参数化csv data set config

    接口测试同一变量或同一组变量不同值时,可通过csv data set config配置数据 1.创建文本文件,写入参数值,一个或一组值为一行,保存为.csv文件 2.创建测试计划,配置元件添加csv ...

  8. sqli-labs less13-20(各种post型头部注入)

    less-13 POST型双查询注入 less-14 POST型双查询注入 less-15 POST型布尔注入 less-16 POST型布尔注入 less-17 POST型报错注入(updatexm ...

  9. Java 12 新特性

    Java 12 已如期于 3 月 19 日正式发布,此次更新是 Java 11 这一长期支持版本发布之后的一次常规更新,截至目前,Java 半年为发布周期,并且不会跳票承诺的发布模式,已经成功运行一年 ...

  10. 开源项目葫芦藤:IdentityServer4的实现及其运用

    目录 前言 签名证书(Signing Credential) 客户端存储(Client Store) 资源存储(Resource Store) 持久化授权存储(Persisted Grant Stor ...