能否取消Spring Bean的代理?

26

我有一个Spring bean,假设它如下所示:

@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public class AImpl implements A {

     public void setSomeDependency(D dependency) {
         // This setter DOES NOT BELONG to interface A
     }
}

<bean id="aImpl" class="AImpl"/>

现在我想要进行集成测试,但是首先我需要模拟依赖项D,因为它做了太多的事情。由于AImpl实现了一个接口并包含一个事务性注解,所以生成的代理只与接口A兼容,因此我可以这样做:

@Inject @Named("aImpl")
private A a;

但是却不能:

@Inject @Named("aImpl")
private AImpl a;

因此,我无法模拟我的依赖关系。

请注意,将void setSomeDependency(D dependency)添加到接口A中不是一个选项,因为它没有业务意义。也不能使用proxy-target-class="true",因为它会影响上下文中的所有bean(此属性会影响上下文中的所有bean)。

有没有一种方法可以取消代理注入的A bean,这样我就可以将其转换为AImpl


@skaffman:感谢您指出这一点,我已将该问题添加到Spring标签FAQ中。 - Tomasz Nurkiewicz
2个回答

38

试试这个:

if(AopUtils.isAopProxy(a) && a instanceof Advised) {
    Object target = ((Advised)a).getTargetSource().getTarget();
    AImpl ai = (AImpl)target;
}

额外附赠:在Scala中,我正在使用以下等效函数来实现完全相同的目的:

def unwrapProxy(a: AnyRef) = a match {
    case advised: Advised if(AopUtils.isAopProxy(advised)) => 
                            advised.getTargetSource.getTarget
    case notProxy => notProxy
}

9
谢谢,你真的救了我。顺便说一下,我第一次去了奥斯陆,现在我也不奇怪为什么你会在 Stack Overflow 上花那么多时间了(没有冒犯之意,但天气并不鼓励人)。 - MaDa
2
很高兴能够帮助。我非常喜欢你的评论,甚至在我的个人资料页面上引用了它;-)。 - Tomasz Nurkiewicz

26

随着Spring 4.2.RC1版本的推出,现在在spring-test模块中有一个专门的工具类来处理这种情况。

该类名为AopTestUtils,提供以下方法:

  • getTargetObject(仅取消包装顶级代理)
  • getUltimateTargetObject(如果存在多层代理,则取消包装多个级别的代理)。

请查看相关的提交记录以及相应的问题


3
感谢提供更新的答案,对于大多数人来说这是更好的解决方案,因为它需要较少的逻辑。 - GreenKiwi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接