Cglib invoke以及invokeSuper的一点区别
简单记录下,解决的一个问题,Cglib的invoke和invokeSuper的区别:
简而言之,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;
一。准备环境 Gglib的两个jar包,因为Cglib使用了ASM生成子类;
二。代码准备
public class Target { public void a() {
System.out.println(" a 方法");
} public void b() {
System.out.println(" b 方法");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MyMethodInterceptor implements MethodInterceptor{ @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//obj是代理后的子类 ,method是调用方法 ,args是方法入参 , proxy是MethodProxy代理对象
System.out.println("myMethodInterceptor go ");
Object res = proxy.invokeSuper(obj, args);
return res;
}
}
测试类:
public class TestApp { public static void main(String[] args) {
Enhancer e = new Enhancer();
e.setSuperclass(Target.class);
e.setCallback(new MyMethodInterceptor());
Target t=(Target) e.create();
t.a();
}
}
测试结果:
myMethodInterceptor go
a 方法
三。
3.1 先解决一个问题,Target这个类里面方法写 this 就是 指的生成的Cglib子类 ,
测试在a方法中添加一句输出this ,结论:Cglib代理的时候target对象中的this就是Cglib子类 (你可能觉得我说的是废话,子类对象在父类的this指的不是自身吗? 你知道Spring Aop里this方法无法增强自身调用,这时候你就开始怀疑人生了)
3.2 既然知道了this对象就是指代的自身,那我比如 this.b() 或者 b() 应该也被回调一次了 。
public class Target { public void a() {
System.out.println(" a 方法");
b();
} public void b() {
System.out.println(" b 方法");
}
}
其他类不改动代码,测试结果如下: 果然 this.b()方法也被增强了;
myMethodInterceptor go
a 方法
myMethodInterceptor go
b 方法
你在 b() 打个断点,下一步就跳进入 MyMethodInterceptor 的 intercept 方法里了 ;这个似乎也没有毛病,其实原因就是 invokeSuper;invokeSuper传入的参数是Cglib代理的子类 ,就相当于 调用 Target$$EnhanceredByCGLIB这个子类的b()方法,肯定会再次进入回调;
3.3 如何实现像AOP一样 调用自身无法增强呢?
修改代码如下: 改动的地方已经标红了 :)
public class Target { public void a() {
System.out.println(" a 方法");
b();
} public void b() {
System.out.println(" b 方法");
}
} public class MyMethodInterceptor implements MethodInterceptor{
private Object target; public MyMethodInterceptor(Object target) {
super();
this.target = target;
} @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("myMethodInterceptor go ");
// Object res = proxy.invokeSuper(obj, args);
Object res = proxy.invoke(target, args);
return res;
} } public class TestApp { public static void main(String[] args) {
// System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\api");
Target target = new Target();
Enhancer e = new Enhancer();
e.setSuperclass(Target.class);
e.setCallback(new MyMethodInterceptor(target));
Target t=(Target) e.create();
t.a();
}
}
测试结果如下:
myMethodInterceptor go
a 方法
b 方法
这就和AOP的功能一毛一样了吧 ; 区别就在于 invoke 和 invokeSuper : 在我理解看来,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;
四。
查看下Spring CGLIB的Aop , 这个就是执行完 环绕通知 、 前置通知 之后执行业务方法的地方 ,target对象存的是原生的bean,没有被CGLIB代理的对象,所以就无法实现自身调用增强;
该方法是 AopUtils的invokeJoinpointUsingReflection
而与之相反的则是,@Configuration注解下类中 @Bean注解标注方法里的 方法调用,得到的是同一个@Bean对象;
因为 BeanMethodInterceptor 的 interceptor方法 调用的invokeSuper方法 ,比如 getMan2方法调用getMan方法,那个getMan方法调用的是 CGLIB子类的getMan方法 ,此时getMan是增强后的getMan方法,这时候就会检测ThreadLocal当前线程和当前方法是否一致了,不一致尝试从容器中获取该bean对象 戳我查看原文
五。查看Cglib生成子类的方案思路
方案一。
测试类上加上这样一句话:
public class TestApp { public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\api");
Target target = new Target();
Enhancer e = new Enhancer();
e.setSuperclass(Target.class);
e.setCallback(new MyMethodInterceptor(target));
Target t=(Target) e.create();
t.a();
}
}
看到控制台输出这样的:
CGLIB debugging enabled, writing to 'E:\api'
myMethodInterceptor go
a 方法
b 方法
可以看到确实生成了CGLIB子类class文件;
我的class文件通过JD-GUI查看却是有些问题 有的地方有很多label ,有知道的怎么解决的评论告诉我 多谢 :)
public final void a()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
if (this.CGLIB$CALLBACK_0 != null)
return;
super.a();
}
方案二。
我觉得是个很神奇的地方,方便以后查看 ,附上作者原文链接,无抄袭的意思 https://blog.csdn.net/lzufeng/article/details/79322391
命令行输入
java -classpath "D:\Java\jdk1.8.0_181\lib\sa-jdi.jar" sun.jvm.hotspot.HSDB
会弹出来一个java工具,选择 File -- > Attach to HotSpot process ,会要求输入进程号
查看方式 新开一个命令行输入
jps -l
可以看到 13592 就是我们需要的;输入刚才的java小工具中,
选择Tool --> Class Browser ,在输入框输入之前的类 Target类
选中下面的CGLIB的子类, 选择Create .class File
文件就生成成功了,找到这个class文件方式很多 ,我测试的时候是在 第一个命令行当前目录下面找到的 ; 此外还可以电脑上文件搜索那个文件名;
(方案三。提供一种思路,可以忽略,因为我也不是很了解这个技术 ,java 探针技术 还是 agent技术 )
Cglib invoke以及invokeSuper的一点区别的更多相关文章
- cglib invoke 和 invokeSuper 可用的组合
在深入字节码理解invokeSuper无限循环的原因中,我们理解的cglib的原理和其中一个合理的调用方式.但是这个调用方式是基于类的,对所有实例生效.实际场景中,我们可能只是希望代理某个具体的实例, ...
- Cglib invoke为什么会死循环?
目录 Cglib invoke为什么会死循环? 动态代理子类的java文件 动态代理子类实例化过程 动态代理类调用过程 动态代理之MethodProxy.invokeSuper Cglib invok ...
- 学习CGLIB与JDK动态代理的区别
动态代理 代理模式是Java中常见的一种模式.代理又分为静态代理和动态代理.静态代理就是显式指定的代理,静态代理的优点是由程序员自行指定代理类并进行编译和运行,缺点是一个代理类只能对一个接口的实现类进 ...
- Atitit 代理CGLIB 动态代理 AspectJ静态代理区别
Atitit 代理CGLIB 动态代理 AspectJ静态代理区别 1.1. AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表:而动态代理则以 spring AOP 为 ...
- POP动画引擎中Layer与CALayer的一点区别
POP动画引擎是facebook提供的一个开源框架, 可以实现很多的动画效果, 这里就不一一介绍啦, 有兴趣的童鞋请移步: https://github.com/facebook/pop 下面简单的讲 ...
- Cglib源码分析 invoke和invokeSuper的差别(转)
原文 https://blog.csdn.net/makecontral/article/details/79593732 Cglib的实例 本文重在源码的分析,Cglib的使用不再复述. //被代理 ...
- 前端框架framework和库library的一点区别和记录
本篇纯文字,无关代码,只是一点概念的记录 关于所谓前端 首先学的是HTML5.CSS3.JavaScript这三个 之后接触了一下UI框架,如layui和bootstrap 目前是打算去学VUE和an ...
- JDK和CGLIB生成动态代理类的区别
关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代 ...
- 【4】JDK和CGLIB生成动态代理类的区别
当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代理:事先写好代理对象类,在 ...
随机推荐
- Java中sleep()与wait()区别(涉及类锁相关概念)
在区别之前,我们首先先了解一下关于对象锁,类锁的相关概念(当时查阅的详细地址:http://www.importnew.com/20444.html,该作者对类锁和对象锁进行了详细的举例分析) 对象锁 ...
- wordpress和数据库的连接
1.首先在数据库里创建wordpress数据库 2.在网页上配置WordPress,安装WordPress 如上配置不对,提交时提示了错误,于是我选择了root用户 123456, 3.提交后,连上了 ...
- unigui作中间件使用
unigui作中间件使用 可返回string或者tstream数据. 如果返回JSON字符,则UNIGUI就是REST 中间件. procedure TUniServerModule.UniGUISe ...
- sqlserver 自动创建作业执行备份数据库
declare @name varchar(250)set @name='I:\dydb_n\dydb_n'+convert(varchar(50),getdate(),112)+ left(righ ...
- 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象
本文需要对C#里的LINQ.Lambda 表达式 .委托有一定了解. 在工作中,经常遇到需要对比两个集合的场景,如: 页面集合数据修改,需要保存到数据库 全量同步上游数据到本系统数据库 在这些场景中, ...
- Asp .Net core 2 学习笔记(1) —— Starup
这个系列的初衷是便于自己总结与回顾,把笔记本上面的东西转移到这里,态度不由得谨慎许多,下面是我参考的资源: ASP.NET Core 中文文档目录 官方文档 记在这里的东西我会不断的完善丰满,对于文章 ...
- ScintillaNET的应用
出于工作需要,需要制作一个嵌入在桌面应用中的C语言编辑器,经过一系列调研,目前ScintillaNET应该是最合适的了,开源.轻便.功能丰富,但是踩得坑也很多,接下面一一说道. 目前Scintilla ...
- dev gridview 设置分组
private void GridConfig() { GridGroupSummaryItem item = new GridGroupSummaryItem(); item.FieldName = ...
- DOM LEVEL 1 中的那些事儿[总结篇-下]
本文承接:DOM LEVEL 1 中的那些事儿[上] 2.3 Element类型 Element类型应该是Document类型之外使用的最多的节点类型了,Element代表XML或HTML文档中的 ...
- AJPFX:外汇的价格图表类型和技术指标类型
AJPFX:价格图表的类型 柱状图 它是反映价格行为的一种最基本的图表.每一根柱代表一段时间——最短为1分钟,最长为数年.随着时间的推移,柱状图反映出不同的价格形态. 蜡烛图 不同于简单的柱状图,蜡烛 ...