当前位置: 首页 > 知识库问答 >
问题:

由于代理,Spring Bean注入失败

汪弘盛
2023-03-14

Spring版本:3.2.4.版本和3.2.9.版本

Mockito版本:1.8.5

我一直在尝试将H2测试引入到一个老项目的集成测试中,并且遇到了一些问题。由于事务传播的方式,我需要模拟一个自动连接的类。我以前这样做过,但是现在遇到了严重的问题。初始化测试时会引发以下错误信息:

org.springframework.beans.factory.BeanCreationException:创建名称为com.stuff.XMLITCase的bean时出错:资源依赖项注入失败;嵌套异常org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为The处理器的Bean必须是[com.stuff.XMLBatchFileProcessor]类型,但实际上是org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:307)的[$Proxy118]类型

再深入一点,就会发现bean实际上是一个代理。如果我们检查AbstractBeanFactory(第239行),我们可以看到代理:

共享实例={$Proxy117@7035} "com.stuff.XMLBatchFileProcessor@66c540d0“h={org.springframework.aop.framework.JdkDynamicAopProxy@7039}

唯一的问题是,我不知道这是从哪里来的。我已经检查了配置和依赖项,找不到任何应该发生这种情况的地方。

不幸的是,我不能为此提供示例项目,但我会检查我的测试配置。我有一个为测试扩展的根类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/spring/spring-test-context.xml"})
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public abstract class AbstractIntegrationTest {
}

这只是加载一些Spring配置,并在每次测试后回滚事务。

spring配置也没什么奇怪的,尽管我的另一个模块和这个模块有一点不同。这是事务管理器和会话工厂:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>

<bean id="hibernateSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
...
</bean>

在我的另一个模块中,我使用的是entityManagerFactory和不同的事务管理器:

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
</bean>

实际的类有一些自动装配的字段,以及通常的@Service注释:

@Service(value = "TheProcessor")
public final class XMLBatchFileProcessor extends BatchFileProcessor implements IXMLBatchProcessor {

最后,实际测试如下:

public class XMLITCase extends AbstractIntegrationTest {

    @Resource(name = "TheProcessor")
    @InjectMocks
    private XMLBatchFileProcessor xmlProcessor;

    @Mock
    private ProcessHelper processHelper;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test() throws Exception {
        Assert.assertNotNull(xmlProcessor);
    }

}

如果我用接口替换XMLBatchFileProcessor并自动连接字段,那么编译就不会有任何问题。然而,Mockito从不使用被模仿的对象替换自动连接的bean。如果是的话,我就不会为@Resource注释和命名服务而烦恼,从而避免了代理问题。

对此如有任何帮助,我们将不胜感激。我将把重点放在会话工厂及其差异上,但很可能我完全忽略了其他一些东西。

根据Sotirios的评论,我今天早上又看了看,确实错过了xmlProcser有一个@Transactional注释,因此这意味着需要代理该类。如果我删除最终声明并让CGLib增强它,那么当initMocks(this)this调用时,Mockito确实会替换bean。然而,当调用方法时,CGLib似乎会将所有bean替换为Spring增强版本,从而覆盖Mockito版本。

在带有@Transactional注释的类的集成测试中,使用Mockito和Spring的正确方法是什么?

共有2个答案

阮健
2023-03-14

您可以使用提供以下方法的类AopTestUtils优化接受的响应:

    < li> getTargetObject以解开顶级代理(如果存在) < Li > < code > getultimatargetobject 以展开所有级别的代理(如果它们存在)
时才俊
2023-03-14

好吧,一旦我意识到由于@Transactional注释,该类被代理,问题的解决方案就变得更加清晰。我需要做的是解开代理的包装,并直接在上面设置模拟对象:

所以在我的< code > AbstractIntegrationTest 中:

/**
 * Checks if the given object is a proxy, and unwraps it if it is.
 *
 * @param bean The object to check
 * @return The unwrapped object that was proxied, else the object
 * @throws Exception
 */
public final Object unwrapProxy(Object bean) throws Exception {
    if (AopUtils.isAopProxy(bean) && bean instanceof Advised) {
        Advised advised = (Advised) bean;
        bean = advised.getTargetSource().getTarget();
    }
    return bean;
}

然后在我的@前中:

@Mock
private ProcessHelper processHelper;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);

    IXMLBatchProcessor iXMLBatchProcessor = (IXMLBatchProcessor) unwrapProxy(xmlProcessor);
    ReflectionTestUtils.setField(iXMLBatchProcessor , "processHelper", processHelper);
}

这使得所有@Autowired类保持不变,同时注入了正确的模拟对象。

 类似资料:
  • 问题内容: 春季版 :3.2.4.RELEASE和3.2.9.RELEASE Mockito版本 :1.8.5 我一直在尝试将H2测试引入一个用于集成测试的旧项目,并且遇到了一些问题。由于事务传播的方式,我需要模拟一个自动装配的类。我以前做过,但是现在遇到了严重的问题。初始化测试时将引发以下错误消息: org.springframework.beans.factory.BeanCreationEx

  • 问题内容: spring版 :3.2.4.RELEASE和3.2.9.RELEASE Mockito版本 :1.8.5 我一直在尝试将H2测试引入一个用于集成测试的旧项目,并且遇到了一些问题。由于事务传播的方式,我需要模拟一个自动装配的类。我以前已经做过,但是现在遇到了严重的问题。初始化测试时将引发以下错误消息: org.springframework.beans.factory.BeanCrea

  • 每https://www.scala-sbt.org/release/docs/Scripts.html我正试图通过征兵安装sbt的替代入口点。我明白了 我能看到https://github.com/sbt/sbt,所以我很困惑...

  • 我有几个EJB3。x无状态会话bean,未定义接口。我需要将这些bean注入到Springbean中,但我无法这样做。 无接口EJB: 我的豆子: 还有我的豆子。xml 在初始化Spring容器时,我得到以下错误: 异常本身非常清楚——spring容器期望MyBean有一个本地接口视图作为其业务接口;但是,我没有(也不能介绍)。 非常感谢您的帮助!

  • 问题内容: 我正在使用一个已定义的拦截器,我想从拦截器中通过DAO层进行db调用,所以我如何将Spring bean注入到struts拦截器中。是否可以将spring bean注入到struts拦截器中,任何人都可以提出任何想法在此。 问题答案: 编辑 由于不需要将拦截器声明为Spring bean,因此删除了不必要的部分。感谢@AleksandrM对其进行测试。 就像使用Actions一样,(如

  • 本文向大家介绍Springbean的几种注入方式都了解吗,包括了Springbean的几种注入方式都了解吗的使用技巧和注意事项,需要的朋友参考一下 Spring注入方式可以分为三类,xml注入、注解注入、BeanDefinition注入;用法上可以分为三种,但是底层实现代码都是统一BeanFactory,这三种也有联系xml注入和annotation注入都是依赖BeanDefinition扩展的接