JDK动态代理案例与原理分析
一、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动态代理的实现原理
原文:http://blog.csdn.net/mhmyqn/article/details/48474815 关于JDK的动态代理,最为人熟知的可能要数Spring AOP的实现,默认情况下,Spr ...
- JDK动态代理实现源码分析
JDK动态代理实现方式 在Spring框架中经典的AOP就是通过动态代理来实现的,Spring分别采用了JDK的动态代理和Cglib动态代理,本文就来分析一下JDK是如何实现动态代理的. 在分析源码之 ...
- JDK动态代理的实现原理
学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504
- jdk动态代理使用及原理
jdk动态代理的使用 1.创建实现InvocationHandler接口的类,实现invoke(Object proxy, Method method, Object[] args)接口,其中invo ...
- Java JDK 动态代理实现和代码分析
JDK 动态代理 内容 一.动态代理解析 1. 代理模式 2. 为什么要使用动态代理 3. JDK 动态代理简单结构图 4. JDK 动态代理实现步骤 5. JDK 动态代理 API 5.1 java ...
- JDK 动态代理 源码简单分析
代理的作用就是在访问真实对象之前或者之后可以额外加入一些操作. JDK 的动态代理 只需要 5 步. 真实对象必须要实现接口,首先创建一个接口 public interface HelloWorld ...
- jdk动态代理 案例
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflec ...
- 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)
代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...
- 解析JDK动态代理实现原理
JDK动态代理使用实例 代理模式的类图如上.关于静态代理的示例网上有很多,在这里就不讲了. 因为本篇讲述要点是JDK动态代理的实现原理,直接从JDK动态代理实例开始. 首先是Subject接口类. p ...
随机推荐
- 从零开始的pickle反序列化学习
前言 在XCTF高校战疫之中,我看到了一道pickle反序列化的题目,但因为太菜了花了好久才做出来,最近正好在学flask,直接配合pickle学一下. 找了半天终于找到一个大佬,这里就结合大佬的文章 ...
- 团队作业part1--团队展示&选题
一.团队展示 1.队名 DiligentVegetableChicken 2.队员信息 纪昂学(组长):3118005053 廖业成:3118005060 蔡越:3118005086 周梓波:3118 ...
- 【Alpha冲刺阶段】Scrum Meeting Daily3
[Alpha冲刺阶段]Scrum Meeting Daily3 1.会议简述 会议开展时间 2020/5/24 8:00-8:15 PM 会议基本内容摘要 每日汇报 个人进度.遇到的困难.明日的计划. ...
- 题解-CF1437F Emotional Fishermen
题面 CF1437F Emotional Fishermen 给 \(n\) 个数的序列 \(a_i\),求有多少种 \(n\) 个数的排列 \(p_i\),使得 \[\frac{a_{p_i}}{\ ...
- PCRE正则表达式语法
字符 描述 \ 将下一个字符标记为一个特殊字符,或一个原义字符,或一个向后引用,或一个八进制转义符.例如,"\n"匹配一个换行符. ^ 匹配输入字符串的开始位置. $ 匹配输入字符 ...
- 为了Java微信支付V3开发包,我找出了微信支付文档至少六个错误
1. 前言 最近忙的一批,难得今天有喘气的机会就赶紧把最近在开发中的一些成果分享出来.前几日分享了自己写的一个微信支付V3的开发包payment-spring-boot-starter,就忙里偷闲完善 ...
- Grafana 备份恢复教程
原文链接:https://fuckcloudnative.io/posts/how-to-back-up-all-of-your-grafana-dashboards/ 目前我们 k8s 集群的 Gr ...
- git远程仓库Github
一.克隆项目 git clone 网址 1.配置信息 git config user.name '用户名' git config user.email '邮箱号' 2.推送项目到远程仓库 # 工作区代 ...
- react第十单元(children的深入用法-React.Children对象上的方法)
第十单元(children的深入用法-React.Children对象上的方法) #课程目标 理解什么是children 掌握React.Children对象上的方法 #知识点 什么是children ...
- [OI笔记]杂题整理1(基础篇~)
算是开学第四周啦,之前的三周大概过了一遍基础图论和数学相关的内容.这篇随笔打算口胡一些近期做感觉比较好的数学相关的题目 因为这段时间主要是看紫书学的,所以其实会有些出自UVA的例题,如果需要题目但是觉 ...