【问题标题】:Spring: Why do we autowire the interface and not the implemented class?Spring:为什么我们自动装配接口而不是实现的类?
【发布时间】:2012-10-05 15:33:25
【问题描述】:

示例

interface IA
{
  public void someFunction();
}

@Resource(name="b")
class B implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someBfunc()
  {
     //doing b things
  }
}

@Resource(name="c")
class C implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someCfunc()
  {
     //doing C things
  }
}

class MyRunner
{

  @Autowire
  @Qualifier("b") 
  IA worker;

  worker.someFunction();
}

谁能给我解释一下。

  • spring 如何知道使用哪种多态类型。
  • 我需要@Qualifier 还是@Resource
  • 为什么我们自动装配接口而不是实现的类?

【问题讨论】:

  • 你可以自动连接接口,这样你就可以连接一个不同的实现——这是编码到接口而不是类的要点之一。
  • 你会在不同的实现中连接;我不明白这个问题。
  • 我认为只为一个实现创建接口是一种愚蠢的做法,在 Java 世界中被接受。结果是一堆垃圾代码,但每个人都很高兴他们遵循了 SOLID 和 OOP 的规则。用诡计,把春天扔进历史的垃圾箱。
  • @chrylis-onstrike- 如果我不打算有不同的功能实现,你能否详细说明为什么我不应该直接注入具体类。在我没有预见到将来会有不同的实现的情况下,接口如何提供帮助。
  • @chrylis-onstrike 你可以在没有接口的情况下进行测试,但是将你的代码撕成一堆由 Spring 粘在一起的小块进行测试是一件愚蠢的事情。

标签: java spring dependency-injection


【解决方案1】:

spring 如何知道使用哪种多态类型。

只要接口只有一个实现,并且该实现用@Component注释并启用了Spring的组件扫描,Spring框架就可以找到(接口,实现)对。如果未启用组件扫描,则必须在 application-config.xml(或等效的 spring 配置文件)中显式定义 bean。

我需要@Qualifier 还是@Resource?

一旦您有多个实现,那么您需要对它们中的每一个进行限定,并且在自动装配期间,您需要使用@Qualifier 注释来注入正确的实现,以及@Autowired 注释。如果您使用@Resource(J2EE 语义),那么您应该使用此注解的name 属性指定bean 名称。

为什么我们自动装配接口而不是实现的类?

首先,一般来说,对接口进行编码总是一个好习惯。其次,在 Spring 的情况下,您可以在运行时注入任何实现。一个典型的用例是在测试阶段注入模拟实现。

interface IA
{
  public void someFunction();
}


class B implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someBfunc()
  {
     //doing b things
  }
}


class C implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someCfunc()
  {
     //doing C things
  }
}

class MyRunner
{
     @Autowire
     @Qualifier("b") 
     IA worker;

     ....
     worker.someFunction();
}

您的 bean 配置应如下所示:

<bean id="b" class="B" />
<bean id="c" class="C" />
<bean id="runner" class="MyRunner" />

或者,如果您在存在这些组件的包上启用了组件扫描,那么您应该使用@Component 限定每个类,如下所示:

interface IA
{
  public void someFunction();
}

@Component(value="b")
class B implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someBfunc()
  {
     //doing b things
  }
}


@Component(value="c")
class C implements IA
{
  public void someFunction()
  {
    //busy code block
  }
  public void someCfunc()
  {
     //doing C things
  }
}

@Component    
class MyRunner
{
     @Autowire
     @Qualifier("b") 
     IA worker;

     ....
     worker.someFunction();
}

然后MyRunner 中的worker 将被注入B 类型的实例。

【讨论】:

  • @stackoverflow 编辑问题没有任何意义,新代码属于答案。否则这个问题没有意义,因为它会自己回答。
  • @VictorDombrovsky @Autowired @Qualifier("a1") a; 有效吗?
  • @Lucky 我犯了一个错误。我的意思是@Autowired @Qualifier("a1") A a;
  • 如果将限定符设置为“b”,那不完全等同于IA worker=new B();?为什么要使用 DI 容器?在我看来,您似乎可以使用基于构造函数的依赖注入并手动实例化类
  • 您甚至可以在实现上使用@Profile 来控制应该通过程序参数或应用程序属性为该接口注入哪个实现。
【解决方案2】:

还可能会在日志中引起一些警告,例如Cglib2AopProxy Unable to proxy method。这里描述了许多其他原因Why always have single implementaion interfaces in service and dao layers?

【讨论】:

    猜你喜欢
    • 2020-03-11
    • 2019-05-19
    • 1970-01-01
    • 2018-11-25
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 2011-01-24
    相关资源
    最近更新 更多