有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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.

他所说的“现在是哪个春天”是什么意思?这是否意味着内部事务调用现在被拦截


你认为什么更好

当您需要一些事务粒度时,您是否拆分了类? 或者您是否使用上述解决方法?(请分享)


共 (3) 个答案

  1. # 1 楼答案

    和往常一样,在建模和设计复杂用例时——关注可理解和可维护的设计和代码。如果您喜欢某个模式或设计,但它与底层框架冲突,那么考虑它是否值得一个复杂的解决方案来将您的设计拖到框架中,或者如果您需要妥协,并将您的设计与必要的框架一致。除非你万不得已,否则不要反对框架

    我的建议是——如果你可以通过一个简单的折衷方案来实现你的目标,比如分成几个额外的服务类——那么就去做吧。就时间、测试和痛苦而言,这听起来比其他选择便宜得多。而且这听起来很容易维护,对下一个接手的人来说也不那么头疼

  2. # 2 楼答案

    我通常把它简化,所以我把代码分成两个对象

    如果需要将所有内容都保存在同一个文件中,可以使用TransactionTemplate来定义新事务。只需再编写几行代码,但只需定义一个新bean即可。这有时会让这一点更加明显

  3. # 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>