Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何处理Spring/EJB/Mockito上的内部调用。。。代理?_Java_Hibernate_Spring_Jakarta Ee_Ejb - Fatal编程技术网

Java 如何处理Spring/EJB/Mockito上的内部调用。。。代理?

Java 如何处理Spring/EJB/Mockito上的内部调用。。。代理?,java,hibernate,spring,jakarta-ee,ejb,Java,Hibernate,Spring,Jakarta Ee,Ejb,许多人都知道,当代理对象时,比如为Spring/EJB创建具有事务属性的bean时,或者甚至在使用某些框架创建部分模拟时,代理对象都不知道这一点,并且内部调用不会重定向,也不会被截获 这就是为什么如果你在春天做这样的事情: @Transactionnal public void doSomething() { doSomethingInNewTransaction(); doSomethingInNewTransaction(); doSomethingInNewTran

许多人都知道,当代理对象时,比如为Spring/EJB创建具有事务属性的bean时,或者甚至在使用某些框架创建部分模拟时,代理对象都不知道这一点,并且内部调用不会重定向,也不会被截获

这就是为什么如果你在春天做这样的事情:

@Transactionnal
public void doSomething() {
    doSomethingInNewTransaction();
    doSomethingInNewTransaction();
    doSomethingInNewTransaction();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomethingInNewTransaction() {
    ...
}
当您调用doSomething时,除了主事务外,您还希望有3个新事务,但实际上,由于这个问题,您只得到一个


所以我想知道你如何处理这些问题

事实上,我必须处理一个复杂的事务系统,我认为没有比将我的服务拆分为许多小服务更好的方法了,这样我就可以通过所有代理

这让我很烦恼,因为所有的代码都属于同一个功能域,不应该被拆分

我发现这个相关的问题有着有趣的答案:

Rob H说我们可以在服务中注入spring代理,并调用proxy.doSomethingInNewTransaction();相反 这是很容易做到的,它的工作,但我真的不喜欢它

侯云峰说,

因此,我编写了自己版本的cglibsubclassinginstationstrategy和 代理创建者,以便使用CGLIB生成一个真正的子类 哪些代理调用它的super而不是另一个实例 春天到了。因此,我可以自由地对任何方法进行注释(只要 因为它不是私有的),无论我在哪里调用这些方法,它们 我们会处理好的。好吧,我还要付出代价:1。我必须列出 我想要启用新CGLIB子类的所有注释 创造2.我不能对最后一种方法进行注释,因为我现在 正在生成子类,因此无法拦截最终方法

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


你认为什么更好

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

我通常会简化它,所以我将代码分为两个对象


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

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


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

我将讨论Spring和@Transactional,但该建议也适用于许多其他框架

这是基于代理的方面的固有问题。spring文档中对此进行了讨论:

有许多可能的解决办法

重构类以避免绕过代理的自调用。

Spring文档将此描述为“最佳方法(这里宽松地使用术语best)”

这种方法的优点是简单,并且与任何框架都没有联系。但是,它可能不适用于事务性很强的代码库,因为最终会得到许多微不足道的小类

在类内部获取代理的引用。

这可以通过注入代理或使用硬编码的“AopContext.currentProxy()”调用(参见上面的Spring文档)来实现

此方法允许您避免拆分类,但在许多方面否定了使用事务性注释的优点。我个人的观点是,这是有点丑陋的事情之一,但丑陋是自足的,如果使用大量交易,这可能是一种务实的方法

切换到使用AspectJ

由于AspectJ不使用代理,因此自调用不是问题

不过,这是一个非常干净的方法——它是以引入另一个框架为代价的。我曾参与过一个大型项目,其中AspectJ就是基于这个原因引入的

根本不要使用@Transactional

重构代码以使用手动事务划分-可能使用decorator模式

这是一个选择,但需要适度的重构,引入额外的框架联系和增加复杂性,因此可能不是首选的选择

我的建议


通常,分解代码是最好的答案,对于分离关注点也是一件好事。但是,如果我有一个很大程度上依赖嵌套事务的框架/应用程序,我会考虑使用AspectJ来允许自调用。你不认为这是一个简单的解决办法吗?@SebastienLorber-我认为这是一个非常好的折衷办法(我自己做过几次,在SpringAOP中绕过这种类型的限制),只要你在javadoc/注释中记录它,以便下一个家伙理解你在做什么以及为什么。这是真的。这个问题是众所周知的,但对于新手来说,javadoc是受欢迎的。。。我仍然想知道什么是“哪个春天?”