回复”666“获取公众号专属资料

记一次“带套路”的面试

//接口
interface Service {void doNeedTx();void doNotneedTx();
}//目标类,实现接口
class ServiceImpl implements Service {@Transactional@Overridepublic void doNeedTx() {System.out.println("execute doNeedTx in ServiceImpl");}//no annotation here@Overridepublic void doNotneedTx() {this.doNeedTx();}
}//代理类,也要实现相同的接口
class ProxyByJdkDynamic implements Service {//包含目标对象private Service target;public ProxyByJdkDynamic(Service target) {this.target = target;}//目标类中此方法带注解,进行特殊处理@Overridepublic void doNeedTx() {//开启事务System.out.println("-> create Tx here in Proxy");//调用目标对象的方法,该方法已在事务中了target.doNeedTx();//提交事务System.out.println("<- commit Tx here in Proxy");}//目标类中此方法没有注解,只做简单的调用@Overridepublic void doNotneedTx() {//直接调用目标对象方法target.doNotneedTx();}
}

//是否是JDK动态代理
System.out.println("isJdkDynamicProxy => " + AopUtils.isJdkDynamicProxy(exampleService));
//是否是CGLIB代理
System.out.println("isCglibProxy => " + AopUtils.isCglibProxy(exampleService));
//代理类的类型
System.out.println("proxyClass => " + exampleService.getClass());
//代理类的父类的类型
System.out.println("parentClass => " + exampleService.getClass().getSuperclass());
//代理类的父类实现的接口
System.out.println("parentClass's interfaces => " + Arrays.asList(exampleService.getClass().getSuperclass().getInterfaces()));
//代理类实现的接口
System.out.println("proxyClass's interfaces => " + Arrays.asList(exampleService.getClass().getInterfaces()));
//代理对象
System.out.println("proxy => " + exampleService);
//目标对象
System.out.println("target => " + AopProxyUtils.getSingletonTarget(exampleService));
//代理对象和目标对象是不是同一个
System.out.println("proxy == target => " + (exampleService == AopProxyUtils.getSingletonTarget(exampleService)));
//目标类的类型
System.out.println("targetClass => " + AopProxyUtils.getSingletonTarget(exampleService).getClass());
//目标类实现的接口
System.out.println("targetClass's interfaces => " + Arrays.asList(AopProxyUtils.getSingletonTarget(exampleService).getClass().getInterfaces()));System.out.println("----------------------------------------------------");//自己模拟的动态代理的测试
Service target = new ServiceImpl();
ProxyByJdkDynamic proxy = new ProxyByJdkDynamic(target);
proxy.doNeedTx();
System.out.println("-------");
proxy.doNotneedTx();
System.out.println("-------");

以下是输出结果:

//是JDK动态代理
isJdkDynamicProxy => true
//不是CGLIB代理
isCglibProxy => false
//代理类的类型,带$的
proxyClass => class com.sun.proxy.$Proxy82
//代理类的父类
parentClass => class java.lang.reflect.Proxy
代理类的父类实现的接口
parentClass's interfaces => [interface java.io.Serializable]
//代理类实现的接口,包含了目标类的接口IExampleService,还有其它的
proxyClass's interfaces => [interface org.eop.sb.example.service.IExampleService,
interface org.springframework.aop.SpringProxy,
interface org.springframework.aop.framework.Advised,
interface org.springframework.core.DecoratingProxy]
//代理对象
proxy => org.eop.sb.example.service.impl.ExampleServiceImpl@54561bc9
//目标对象
target => org.eop.sb.example.service.impl.ExampleServiceImpl@54561bc9
//代理对象和目标对象输出的都是@54561bc9,还真有点懵逼
//进行测试后发现,其实不是同一个,只是toString()的问题
proxy == target => false
//目标类,我们自己写的
targetClass => class org.eop.sb.example.service.impl.ExampleServiceImpl
//目标类实现的接口,我们自己写的
targetClass's interfaces => [interface org.eop.sb.example.service.IExampleService]
----------------------------------------------------
//带注解的方法调用,有事务的开启和提交
-> create Tx here in Proxy
execute doNeedTx in ServiceImpl
<- commit Tx here in Proxy
-------
//没有注解的方法调用,是没有事务的
execute doNeedTx in ServiceImpl
-------

class Target {@Transactionalpublic void doNeedTx() {System.out.println("execute doNeedTx in Target");}//no annotation herepublic void doNotneedTx() {this.doNeedTx();}
}class ProxyByCGLIB extends Target {private Target target;public ProxyByCGLIB(Target target) {this.target = target;}@Overridepublic void doNeedTx() {System.out.println("-> create Tx in Proxy");target.doNeedTx();System.out.println("<- commit Tx in Proxy");}@Overridepublic void doNotneedTx() {target.doNotneedTx();}
}

//不是JDK动态代理
isJdkDynamicProxy => false
//是CGLIB代理
isCglibProxy => true
//生成的代理类的类型,带$$的
proxyClass => class org.eop.sb.example.service.impl.ExampleServiceImpl$$EnhancerBySpringCGLIB$$5320b86e
//代理类的父类,就是目标类
parentClass => class org.eop.sb.example.service.impl.ExampleServiceImpl
//父类实现的接口,就是我们自己写的接口
parentClass's interfaces => [interface org.eop.sb.example.service.IExampleService]
/**代理类实现的接口,并不包含目标类的接口*/
proxyClass's interfaces => [interface org.springframework.aop.SpringProxy,
interface org.springframework.aop.framework.Advised,
interface org.springframework.cglib.proxy.Factory]
//代理对象
proxy => org.eop.sb.example.service.impl.ExampleServiceImpl@1b2702b1
//目标对象
target => org.eop.sb.example.service.impl.ExampleServiceImpl@1b2702b1
//代理对象和目标对象不是同一个
proxy == target => false
//目标类,我们自己写的类
targetClass => class org.eop.sb.example.service.impl.ExampleServiceImpl
//目标类实现的接口
targetClass's interfaces => [interface org.eop.sb.example.service.IExampleService]

由于采用的是相同的测试代码,所以目标类是实现了接口的,不过这并不影响使用CGLIB来生成代理。可见,代理类确实继承了目标类以保持和目标类的类型兼容,对外接口相同。注:只要是以代理方式实现的声明式事务,无论是JDK动态代理,还是CGLIB直接写字节码生成代理,都只有public方法上的事务注解才起作用。而且必须在代理类外部调用才行,如果直接在目标类里面调用,事务照样不起作用。

后记

想知道更多?描下面的二维码关注我


加技术群入口(备注:Tech):

免费星球入口:

免费资料入口:后台回复“666”

朕已阅 

Spring事务“套路”面试相关推荐

  1. 【面试1v1实景模拟】Spring事务经典面试场景,全方位解读面试官心理,助你面试入坑~

    笑小枫专属目录 老面

  2. 【面试】我是如何在面试别人Spring事务时“套路”对方的

    作者:李新杰,来自:编程新说 "中国最好面试官" 自从上次写了一篇"[面试]我是如何面试别人List相关知识的,深度有点长文"的文章后,有读者专门加我微信,说我 ...

  3. 我是如何在面试别人Spring事务时“套路”对方的

    "中国最好面试官" 自从上次写了一篇"[面试]我是如何面试别人List相关知识的"的文章后,有读者专门加我微信,说我是"中国最好面试官",这 ...

  4. 聊聊我是如何在面试别人Spring事务时“套路”对方的

    戳蓝字"CSDN云计算"关注我们哦! "中国最好面试官" 我希望把面试当作是一次交流,像朋友那样,而不是像一场Q & A.但也有人觉得,我对应聘者&qu ...

  5. spring 事务原理_Spring声明式事务处理的实现原理,来自面试官的穷追拷问

    公众号[JavaQ]原创,专注分享Java基础原理分析.实战技术.微服务架构.分布式系统构建,诚邀点赞关注! 面试官:有如下代码场景,A类的a1方法没有标注@Transactional注解,a2方法标 ...

  6. (转)面试必备技能:JDK动态代理给Spring事务埋下的坑!

    一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...

  7. spring的事务隔离_再深一点:面试工作两不误,源码级理解Spring事务

    原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非 ...

  8. 面试官: 讲讲 Spring 事务有哪些坑?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 引言 今天,我们来讲 Spring 中和事务有关的考题. ...

  9. 再深一点:面试工作两不误,源码级理解Spring事务

    原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. Spring有5种隔离级别,7种传播行为.这是面试常问的内容,也是代码中经常碰到的知识点.这些知识枯燥而且乏味,其中有些非 ...

最新文章

  1. cuda 判断nan 处理办法
  2. 04号团队-团队任务3:每日立会(2018-11-27)
  3. Java 反射将配置文件数据加载到对象属性中
  4. 下巴长痘痘是什么原因?要怎么解决?(实用教程)
  5. oracle查询sql时间ain,Oracle SQL 时间查询
  6. 《Netty Zookeeper Redis 高并发实战》 图书简介
  7. 全国python工程师有多少_2019年Python工程师的平均薪资是多少?
  8. 旋转矩阵中6保6_旋转矩阵公式中6保5
  9. JavaScript(BOM、窗口事件和计时器)
  10. 项目管理之成熟度模型
  11. python解决乱码转成中文
  12. 物联网终端有哪些应用
  13. 【人工翻译线代教材】Introduction to Linear Algebra BY Gilbert Strang【MIT】【线代】【翻译】
  14. 读书笔记 - 《经济学通识》
  15. Windows下使用smb搭建你的个人云盘(ipad不止爱奇艺)
  16. mx4 pro 刷 原生 android,如期而至:MX4 Pro 迎来首个 Android 5.0 体验固件
  17. qq动态名片代码_利用Python动态爬取QQ说说并生成词云,分析朋友状况!
  18. Python:绘制动态地图-pyecharts
  19. 不务正业——游记篇 no.1 (重庆)
  20. 线性表的练习--学生成绩统计

热门文章

  1. webflux系列--reactor功能
  2. 1984年王安微型计算机,王安简:今年中科大少年班最小的学生
  3. des算法明文IP置换C语言编程,求助攻:C语言DES算法的实现程序有问题
  4. python的md5
  5. 200908阶段一C++多态
  6. 让你不再害怕指针的应用-全程仿真+注解(第二部分数组)
  7. 验证视图状态MAC失败的解决办法
  8. php编译安装与配置
  9. 零元学Expression Blend 4 - Chapter 38 看如何使用Clip修出想要的完美曲线(下)
  10. 内存泄漏的常见应用领域