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 ...
随机推荐
- Leetcode学习笔记(6)
题目1 ID112 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和. 说明: 叶子节点是指没有子节点的节点. 示例: 给定如下二叉树,以及目标 ...
- NET core 添加了新的nuget包,部署出现Could not load file or assembly
这个坑,今天整了一天,我添加了Microsoft.AspNetCore.Mvc.Versioning包,结果发布到服务器,我复制了dll过去出现了一直找不到加载不成功的问题 Startup.Confi ...
- LeetCode初级算法之数组:1 两数之和
两数之和 题目地址:https://leetcode-cn.com/problems/two-sum/ 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个整 ...
- 深入理解.NET/WPF内存泄漏
众所周知,内存管理和如何避免内存泄漏(memory leak)一直是软件开发的难题.不要说C.C++等非托管(unmanaged)语言,即使是Java..NET等托管(managed)语言,尽管有着完 ...
- 【HNOI2010】城市建设(对时间分治 & Kruskal)
Description \(n\) 个点 \(m\) 条边的带边权无向图.\(q\) 次操作,每次修改一条边的权值. 求每次修改后的最小生成树的边权和. Hint \(1\le n\le 2\time ...
- 【Codeforces 1037H】Security(SAM & 线段树合并)
Description 给出一个字符串 \(S\). 给出 \(Q\) 个操作,给出 \(L, R, T\),求字典序最小的 \(S_1\),使得 \(S^\prime\) 为\(S[L..R]\) ...
- sql 遍历list
<select id="findadminSaleList" parameterClass="java.util.Map" resultClass=&qu ...
- 廖雪峰官网学习js 字符串
操作字符串: length() 长度 totoLowerCase() 小写 toUpperCase() 大写 trim() 移除空白 charAt( ...
- 购物车 python作业
功能要求:要求用户输入总资产,例如:2000显示商品列表,让用户根据序号选择商品,加入购物车购买,如果商品总额大于总资产,提示账户余额不足,否则,购买成功.附加:可充值.某商品移除购物车goods = ...
- Python不同包之间调用注意事项
1.不同包之间调用,因为在不同文件夹下,引用的时候加上包名就可以了.运行时,在eclipse直接运行没有问题.但是在,命令行运行时出现找不到模块的错误.原因是,Python只搜索当前目录和内置模块以及 ...