spring ioc注入接口的具体实现来测试

发布于 2024-08-14 11:11:46 字数 1461 浏览 4 评论 0原文

我有以下设置:

@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 中删除“implements 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 才能注入具体实现的想法。

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

I have the following setup:

@Component
public class ImplOne implements IFace{
}

@Component
public class ImplTwo implements IFace{
}

public interface IFace{
}

I am trying to get a reference of ImplOne by type:

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

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

Though with this I get the following exception:

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)}

I tried the following workarounds:

  • Remove "implements IFace" from ImplOne so the implementation class itself gets Proxied by cglib. Not acceptable because I also need to be able to get all implementations of IFace in my application code.
  • Doing method injection via a @Autowired public void setImplOne(IFace[] beans) and filtering the instance through instanceof check does not work, because the injected beans are subclasses of type java.lang.reflect.Proxy which doesn't offer any useful methods.
  • Changing @Component of ImplOne to @Component("implone") and using @Qualifier("implone").

Code:

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

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

But I don't like the idea of having to name my beans just to be able to inject the concrete implementation.

Is there some way to do this elegantly, or atleast in some manner that only affects my test code? Also is there some special reason why my first example is unsupported?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

箜明 2024-08-21 11:11:46
  1. 检查异常是否与您认为的豆有关。因为名称不匹配
  2. 即使 1 是固定的,最好通过接口自动装配,而不是通过具体实现。大多数情况下(我不知道您的情况是否属实),具体实现由 spring 代理(例如,用于事务支持),并且只能通过接口注入。由于一个接口有两个实现,因此您必须提供一个名称,并使用 @Autowired + @Qualifier 或使用 @Resource(name= "") 来注入你想要的东西。这并没有什么问题。
  1. Check if the exception is about the beans you think it is. Because the names don't match
  2. Even if 1 is fixed, it is preferable to autowire by interface, not by concrete implementation. Most often (I can' know if this is true in your case), concrete implementations are proxied by spring (for transaction support, for example), and can be injected by interface only. And since you have two implementations of one interface, you have to provide a name, and either use @Autowired + @Qualifier, or use @Resource(name="") to inject what you want. And there is nothing wrong with this.
森林散布 2024-08-21 11:11:46

好吧,今天我终于找到了一种方法来完成这项工作。看来 Spring-AOP-Autoproxy 应该为这个不起作用负责。

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

<aop:pointcut id="serviceOperation" expression="execution(* some.package..*(..)) && @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对我不起作用的原因......

Ok, today i found a way to make this work afterall. Seems like the Spring-AOP-Autoproxy was to blame for this not to work.

Currently I am using AJDT in Eclipse for compile time weaving (CTW) and the TransactionAnnotationAspect. I also removed the aspectjweaver and cglib dependency in my project, so autoproxy is not even supported anymore, after removing the following config part from applicationcontext:

<aop:pointcut id="serviceOperation" expression="execution(* some.package..*(..)) && @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>

And that was also the reason why @Configurable didn't work for me...

雨后咖啡店 2024-08-21 11:11:46

添加以下行对我有用:

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

Adding the following line worked for me:

<aop:aspectj-autoproxy proxy-target-class="true"/>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文