java如何处理Spring/EJB/Mockito上的内部调用。。。代理?
许多人都知道,当代理对象时,比如为Spring/EJB创建具有事务属性的bean时,或者甚至在使用某些框架创建部分模拟时,代理对象都不知道这一点,并且内部调用不会重定向,也不会被截获
这就是为什么如果你在春天做这样的事情:
@Transactionnal
public void doSomething() {
doSomethingInNewTransaction();
doSomethingInNewTransaction();
doSomethingInNewTransaction();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomethingInNewTransaction() {
...
}
当您调用doSomething时,除了主事务外,您还希望有3个新事务,但实际上,由于这个问题,您只得到一个
所以我想知道你如何处理这些问题
事实上,我必须处理一个复杂的事务系统,我认为没有比将我的服务拆分为许多小服务更好的方法了,这样我就可以通过所有代理
这让我很烦恼,因为所有的代码都属于同一个功能域,不应该被拆分
我发现这个相关的问题有着有趣的答案: Spring - @Transactional - What happens in background?
Rob H说我们可以在服务中注入spring代理,并调用代理。doSomethingInNewTransaction();相反 这是很容易做到的,它的工作,但我真的不喜欢它
侯云峰说,
So I write my own version of CglibSubclassingInstantiationStrategy and proxy creator so that it will use CGLIB to generate a real subclass which delegates call to its super rather than another instance, which Spring is doing now. So I can freely annotate on any methods(as long as it is not private), and from wherever I call these methods, they will be taken care of. Well, I still have price to pay: 1. I must list all annotations that I want to enable the new CGLIB sub class creation. 2. I can not annotate on a final method since I am now generating subclass, so a final method can not be intercepted.
他所说的“现在是哪个春天”是什么意思?这是否意味着内部事务调用现在被拦截
你认为什么更好
当您需要一些事务粒度时,您是否拆分了类? 或者您是否使用上述解决方法?(请分享)
# 1 楼答案
和往常一样,在建模和设计复杂用例时——关注可理解和可维护的设计和代码。如果您喜欢某个模式或设计,但它与底层框架冲突,那么考虑它是否值得一个复杂的解决方案来将您的设计拖到框架中,或者如果您需要妥协,并将您的设计与必要的框架一致。除非你万不得已,否则不要反对框架
我的建议是——如果你可以通过一个简单的折衷方案来实现你的目标,比如分成几个额外的服务类——那么就去做吧。就时间、测试和痛苦而言,这听起来比其他选择便宜得多。而且这听起来很容易维护,对下一个接手的人来说也不那么头疼
# 2 楼答案
我通常把它简化,所以我把代码分成两个对象
如果需要将所有内容都保存在同一个文件中,可以使用TransactionTemplate来定义新事务。只需再编写几行代码,但只需定义一个新bean即可。这有时会让这一点更加明显
# 3 楼答案
我将讨论Spring和@Transactional,但建议也适用于许多其他框架
这是基于代理的方面的固有问题。spring文档中对此进行了讨论:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
有许多可能的解决办法
重构类以避免绕过代理的自调用调用强>
Spring文档将此描述为“最佳方法(这里宽松地使用术语best)”
这种方法的优点是简单,并且与任何框架都没有联系。但是,它可能不适用于事务性很强的代码库,因为最终会得到许多微不足道的小类
在类内部获取对代理的引用强>
这可以通过注入代理或使用硬编码的“AopContext.currentProxy()”调用(参见上面的Spring文档)来实现
此方法允许您避免拆分类,但在许多方面否定了使用事务性注释的优点。我个人的观点是,这是有点丑陋的事情之一,但丑陋是自足的,如果使用大量交易,这可能是一种务实的方法
切换到使用AspectJ
由于AspectJ不使用代理,因此自调用不是问题
不过,这是一个非常干净的方法——它是以引入另一个框架为代价的。我曾参与过一个大型项目,其中AspectJ就是基于这个原因引入的
根本不要使用@Transactional
重构代码以使用手动事务划分-可能使用decorator模式
这是一个选择,但需要适度的重构,引入额外的框架联系和增加复杂性,因此可能不是首选的选择
我的建议
通常,分解代码是最好的答案,对于分离关注点也是一件好事。但是,如果我有一个很大程度上依赖嵌套事务的框架/应用程序,我会考虑使用AspectJ来允许自调用。p>