【问题标题】:spring ioc injecting concrete implementation of interface to testspring ioc注入接口的具体实现进行测试
【发布时间】:2010-12-25 08:58:19
【问题描述】:

我有以下设置:

@Component
public class ImplOne implements IFace{
}

@Component
public class ImplTwo implements IFace{
}

public interface IFace{
}

我正在尝试按类型获取 ImplOne 的参考:

@RunWith(SpringJUnit4ClassRunner.class)
public class ImplOneTest {
  @Autowired
  private ImplOne impl;

  @Test
  public void test(){
    Assert.assertNotNull(impl);
  }
}

虽然这样我得到以下异常:

org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [some.package.TestBean] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

我尝试了以下解决方法:

  • 从 ImplOne 中删除“实现 IFace”,以便实现类本身由 cglib 代理。不可接受,因为我还需要能够在我的应用程序代码中获得 IFace 的所有实现。
  • 通过 @Autowired public void setImplOne(IFace[] beans) 进行方法注入并通过 instanceof 检查过滤实例不起作用,因为注入的 bean 是 java.lang.reflect 类型的子类.Proxy 不提供任何有用的方法。
  • 将 ImplOne 的 @Component 更改为 @Component("implone") 并使用 @Qualifier("implone")。

代码:

@RunWith(SpringJUnit4ClassRunner.class)
public class ImplOneTest {
  @Autowired
  @Qualifier("implone")
  private ImplOne impl;

  @Test
  public void test(){
    Assert.assertNotNull(impl);
  }
}

但我不喜欢为了能够注入具体实现而必须命名我的 bean 的想法。

有什么方法可以优雅地做到这一点,或者至少以某种方式只影响我的测试代码?还有一些特殊原因导致我的第一个示例不受支持吗?

【问题讨论】:

  • 异常表明问题不在于 ImplOne 引用,而在于找不到的 de.investdwin.gemeinsam.abstrakt.TestBean 引用。您是否有可能在 Spring 配置中的某个地方遗漏其中之一?
  • 我在发这个问题的时候重命名了bean,原来是TestBean
  • 我尝试命名 bean 并使用 @Qualifier,但没有成功。我什至只有一个具体的实现。 @Qualifier 仅用于解决歧义(如果有),否则将被忽略。因此,除非您有多个实现,否则使用 @Qualifier 没有任何区别。我想知道你怎么可能让它工作,因为问题不是模棱两可,而是根本没有一个具有指定匹配类型的 bean。

标签: spring dependency-injection inversion-of-control javabeans


【解决方案1】:
  1. 检查异常是否与您认为的 bean 有关。因为名字不匹配
  2. 即使 1 是固定的,最好按接口自动装配,而不是按具体实现。大多数情况下(我不知道在你的情况下这是否属实),具体实现由 spring 代理(例如,用于事务支持),并且只能通过接口注入。而且由于你有一个接口的两种实现,你必须提供一个名称,或者使用@Autowired + @Qualifier,或者使用@Resource(name="") 来注入你想要的东西。这并没有错。

【讨论】:

  • 或者把primary="true"放在首选的bean定义上,或者把autowire-candidate="false"放在另一个上
  • hmm,那么每个 bean 都将是 primary="true",尽管这不是仅 xml 吗?好像我被这些名字困住了。我可能会使用 public static final String NAME = "implOne" 并在注释中引用它,所以我没有两个地方来维护这些名称。
【解决方案2】:

好的,今天我终于找到了一种方法来完成这项工作。似乎 Spring-AOP-Autoproxy 应该归咎于这不起作用。

目前我在 Eclipse 中使用 AJDT 进行编译时编织 (CTW) 和 TransactionAnnotationAspect。我还删除了项目中的 aspectjweaver 和 cglib 依赖项,因此在从 applicationcontext 中删除以下配置部分后,甚至不再支持 autoproxy:

<aop:pointcut id="serviceOperation" expression="execution(* some.package..*(..)) &amp;&amp; @target(org.springframework.stereotype.Service)" />
    <aop:advisor pointcut-ref="serviceOperation" advice-ref="serviceTxAdvice" />
</aop:config>
<tx:advice id="serviceTxAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" read-only="true" propagation="SUPPORTS" />
    </tx:attributes>
</tx:advice>

这也是@Configurable 对我不起作用的原因...

【讨论】:

    【解决方案3】:

    添加以下行对我有用:

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多