动态代理-cglib分析
生成代理类文件的方式
jvm添加此启动参数,后面就是代理类class生成的地址
-Dcglib.debugLocation=~/baldhead/java/dynamic-proxy-cglib/src/main/java/com/baldhead/dynamic/proxy/cglib/class
添加这个参数之后,CGLIB就会把生成的代理Class文件存在指定的路径
生成动态代理对象流程
- CGLIB首先生成代理类
- 代码中的 static 静态代码块 会调用
CGLIB$STATICHOOK1();方法,方法作用
3. 新建一个名字为CGLIB$THREAD_CALLBACKS的ThreadLocal,用来存放所设置的callback
4. 使用反射找到代理类中的所有方法,包括(toString、hashCode、equals、clone),名字为模板CGLIB$METHODNAME$数字编号$Method
并且给对应的方法创建代理方法 名字模板CGLIB$METHODNAME$数字编号$Proxy - 调用构造方法创建代理对象
- 然后CGLIB会调用代理对象的
CGLIB$SET_THREAD_CALLBACKS方法,将传入的callBack存到ThreadLocal(CGLIB$THREAD_CALLBACKS)中去 - 后续在对象执行需要代理的方法的时候,就会从
CGLIB$THREAD_CALLBACKS中拿到所设置的CallBack并调用它的intercept()方法
代理对象的创建
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService$$EnhancerByCGLIB$$e34eec9a");
Class var1;
CGLIB$test$0$Method = ReflectUtils.findMethods(new String[]{"test", "()V"}, (var1 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService")).getDeclaredMethods())[0];
CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0");
}
以上代码经过简化的,主要看下面给出的一行
CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0");
对应的方法如下
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
/**
* 这几个参数都可以找到入参对象
* c1: 被代理类对象的class,也就是原始对象的class
* c2: 代理类对象的 class
* desc: 方法的返回值类型
* name1: 原始代理方法的名称
* name2: 代理方法在代理类中的名称(CGLIB$test$0)
*/
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
在MethodProxy中有三个很重要的属性
- sig1: 表示test方法
- sig2: 表示 CGLIB$test$0 方法
- createInfo: 表示原始类和代理类
invoke和invokeSuper方法
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
this.init();
FastClassInfo fci = this.fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
if (this.fastClassInfo.i1 < 0) {
throw new IllegalArgumentException("Protected method: " + this.sig1);
} else {
throw var5;
}
}
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
两个方法大差不差的,但是都用到了一个对象 fastClassInfo 这个对象是在 init()方法中构造的
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
CreateInfo ci = this.createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
fastClassInfo对象中主要是有四个属性
- f1: 原始类对应的一个FastClass 代理对象
- f2: 代理类对应的一个FastClass 代理对象
- i1: test方法在原始类对应的一个FastClass代理对象中的下标
- i2: CGLIB$test$0方法在代理类对应的一个 FastClass 代理对象中的下标
这里产生了两个代理对象,你说好巧不巧,正好产生的代理,class有3个,其中有两个继承 FastClass, 另外一个继承原始类并且实现 Factory接口

其实这两个类类似,都是针对某一个类的FastClass代理类,所以我们好好看一下UserService所对应的FastClass该类主要有:
- 一个构造方法
public int getlndex(Signature var1)public int getlndex(String var1, Classll var2)public int getlndex(ClassI var1)public Object invoke(int var1, Object ar2, Objectll var3)public Object newlnstance(int var1, Objectll var2)public int getMaxlndex0
顾名思义,FastClass的作用是提高方法的执行速度,按照正常的实现,当我们调用MethodProxy对象的invokel或invokeSuper0方法时,首先应该要做到的就是找到对应的Method对象,比如:
执行invoke0,要找到test方法对应的Method对象
执行invokeSuper0,要找到CGLIBstest$00方法对应的Method对象然后利用反射来执行Method。
那么FastClass的机制就是预先把UserService类或UserService代理类中的所有方法做一个索引,比如:
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch (var10000.hashCode()) {
case -2055565910:
if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 19;
}
break;
case -1659690448:
if (var10000.equals("CGLIB$test$4()V")) {
return 20;
}
break;
case -1457535688:
if (var10000.equals("CGLIB$STATICHOOK1()V")) {
return 12;
}
break;
case -1422510685:
if (var10000.equals("test()V")) {
return 7;
}
break;
case -1411872516:
if (var10000.equals("CGLIB$hashCode$2()I")) {
return 15;
}
break;
// 省略部分代码
}
return -1;
}
一旦调用 getIndex(Signature var1) 方法,就对得到对应方法返回的索引,例如这里就是test方法返回的对应的索引就是7
再回到init 方法
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
CreateInfo ci = this.createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
init方法中的两个 helper方法就是去生成原始类和代理类的 FactClass代理类,后面个两个getIndex方法
1. 第一个fci.f1.getIndex(this.sig1)就是去获取原始类对应的FastClass代理类中 test方法的下标i1
2. 第二个 fci.f2.getIndex(this.sig2)就是去获取代理类对应的FastClass代理类中$test$0方法的下标i2
然后会把两个下标都记录在 fastClassInfo 对象中
后面就是我们看到的invoke和invokeSuper中调用的两个方法
invoke
fci.f1.invoke(fci.i1, obj, args);执行原始类对应的FastClass 代理类的invoke方法
invokeSuper
fci.f2.invoke(fci.i2, obj, args);执行代理类对应的
FastClass代理类的invoke方法
例如: 原始类对应的FastClass 代码
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
UserService var10000 = (UserService)var2;
int var10001 = var1;
try {
switch (var10001) {
case 0:
var10000.test();
return null;
case 1:
return new Boolean(var10000.equals(var3[0]));
case 2:
return var10000.toString();
case 3:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
这个代码比较简单,第一个参数就是执行方法的index,第二个参数就是原始类,第三个就是原始类的参数
如果传入的index 是0 ,那么就会去执行test方法
代理类对应的FastClass代理类的invoke方法也是类似
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
UserService..EnhancerByCGLIB..e34eec9a var10000 = (UserService..EnhancerByCGLIB..e34eec9a)var2;
int var10001 = var1;
try {
switch (var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.clone();
case 4:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 5:
return var10000.newInstance((Callback[])var3[0]);
case 6:
return var10000.newInstance((Callback)var3[0]);
case 7:
var10000.test();
return null;
case 8:
e34eec9a.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 9:
e34eec9a.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 10:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 11:
return var10000.getCallback(((Number)var3[0]).intValue());
case 12:
return var10000.getCallbacks();
case 13:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 14:
return e34eec9a.CGLIB$findMethodProxy((Signature)var3[0]);
case 15:
e34eec9a.CGLIB$STATICHOOK1();
return null;
case 16:
var10000.CGLIB$test$0();
return null;
case 17:
return new Integer(var10000.CGLIB$hashCode$3());
case 18:
return new Boolean(var10000.CGLIB$equals$1(var3[0]));
case 19:
return var10000.CGLIB$toString$2();
case 20:
return var10000.CGLIB$clone$4();
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
例如传入的index 是16 那么执行的就是 var10000.CGLIB$test$0();
如果传入的index是 7 那么执行的就是var10000.test();
var10000 是传入对象强转为UserService..EnhancerByCGLIB..e34eec9a类的对象,UserService..EnhancerByCGLIB..e34eec9a类其实就是UserService的代理类
invokeSuper结论
所以当我们执行invokeSuper方法的时候,不能传入原始类(UserService)只能传入代理类对象,不然就无法转换成为代理类类型
所以FastClass 快的地方就是预先把所有的方法信息都生成了对应的index,在真正的去执行的时候不用再去找Method对象,直接传入对应方法的index就可以直接执行对应的方法了
动态代理-cglib分析的更多相关文章
- Java代理和动态代理机制分析和应用
本博文中项目代码已开源下载地址:GitHub Java代理和动态代理机制分析和应用 概述 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息 ...
- Proxy 代理模式 动态代理 cglib MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Java 动态代理机制分析及扩展
Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...
- 获取JDK动态代理/CGLIB代理对象代理的目标对象。
问题描述:: 我现在遇到个棘手的问题,要通过spring托管的service类保存对象,这个类是通过反射拿到的,经过实验发现这个类只能反射取得sservice实现了接口的方法,而extends类的方法 ...
- java:java静态代理与动态代理简单分析
java静态代理与动态代理简单分析 转载自:http://www.cnblogs.com/V1haoge/p/5860749.html 1.动态代理(Dynamic Proxy) 代理分为静态代理和动 ...
- Java 动态代理机制分析及扩展,第 1 部分
Java 动态代理机制分析及扩展,第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ 本文通过分析 Java 动态代理的机制和特 ...
- 基于JDK的动态代理原理分析
基于JDK的动态代理原理分析 这篇文章解决三个问题: What 动态代理是什么 How 动态代理怎么用 Why 动态代理的原理 动态代理是什么? 动态代理是代理模式的一种具体实现,是指在程序运行期间, ...
- cglib源码分析(四):cglib 动态代理原理分析
本文分下面三个部分来分析cglib动态代理的原理. cglib 动态代理示例 代理类分析 Fastclass 机制分析 一.cglib 动态代理示例 public class Target{ publ ...
- 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)
代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...
- Java动态代理全面分析
代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1 主题:规定代理类和真实对象共同对外暴露的接口: 2 代理类:专门代理真实对象的类: 3 ...
随机推荐
- Excel中的VLOOKUP函数
VLOOKUP函数是Excel中的一个纵向查找函数,功能是按列查找,最终返回该列所需查询序列所对应的值. 该函数的语法规则如下: VLOOKUP(lookup_value,table_array,co ...
- Codeforces Round #786 (Div. 3) 补题记录
小结: A,B,F 切,C 没写 1ll 对照样例才发现,E,G 对照样例过,D 对照样例+看了其他人代码(主要急于看后面的题,能调出来的但偷懒了. CF1674A Number Transforma ...
- vulnhub靶场之DEATHNOTE: 1
准备: 攻击机:虚拟机kali.本机win10. 靶机:DEATHNOTE: 1,网段地址我这里设置的桥接,所以与本机电脑在同一网段,下载地址:https://download.vulnhub.com ...
- 13.django-admin组件
Django内置了一个强大的组件叫Admin,提供给网站管理员快速开发运营后台的管理站点,下面通过案例进行操作 1.创建模型类 模型类如下: from django.db import models ...
- 系统内置APK并签名并配置AndroidStudio
前言 最近在集成内置APK的时候遇到了些问题,遂整理一份文档以记录. 一,APP内置进系统固件 将APK源码或编译出的apk文件放在package或vendor等目录下,并且编写相应的android, ...
- 一张VR图像帧的生命周期
"VR 应用程序每帧渲染两张图像,一张用于左眼,一张用于右眼."人们通常这样来解释 VR 渲染,虽然没有错,但可能过于简单化了.对于 Quest 开发人员来说,了解全貌是有益的,这 ...
- sublime text设置build system automatic提示no build system
解决办法: 将: "selector": "source.asm" 改为: "selector": ["source.asm&qu ...
- 多表查询、Navicat软件、PyMySQL模块
目录 多表查询.Navicat软件.PyMySQL模块 一.多表查询的两种方法 1.准备工作 2.第一种:连表操作 3.第二种:子查询 总结与结论: 二.多表查询练习题 1.课堂多表查询练习题 2.以 ...
- 初次邂逅 EasyExcel
前言 由于工作原因,有这种需求,就是把数据库中的数据导出成 Excel 表格,同时,也得支持人家用 Excel 表格导入数据到数据库.当前项目也是在用 EasyExcel,所以我不得不学啦! 以前学习 ...
- [论文阅读] 颜色迁移-Correlated Color Space
[论文阅读] 颜色迁移-Correlated Color Space 文章: Color transfer in correlated color space, [paper], [matlab co ...