178

Example

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

Can someone explain this to me.

  • How does spring know which polymorphic type to use.
  • Do I need @Qualifier or @Resource?
  • Why do we autowire the interface and not the implemented class?
stackoverflow
  • 18,348
  • 50
  • 129
  • 196
  • 15
    You autowire the interface so you can wire in a *different* implementation--that's one of the points of coding to the interface, not the class. – Dave Newton Oct 15 '12 at 15:55
  • You'd wire in a different implementation; I don't understand the question. – Dave Newton Oct 15 '12 at 16:03
  • If we are wiring in the interface, what happens when there's a default visibility method within the Impl class that I need access to? I can't add that method stub to the interface because public Interface can't contain default modifier. – jlewkovich Dec 12 '16 at 20:42
  • Possible duplicate of [Spring Autowiring class vs. interface?](https://stackoverflow.com/questions/2387431/spring-autowiring-class-vs-interface) – OhadR Jun 24 '17 at 15:37
  • 5
    I think making an interface for only one implementation is a stupid practice that is accepted in the java world. The result is a lot of garbage code, but everyone is happy that they followed the rules of SOLID and OOP. Use the guice and throw the spring in the dustbin of history. – avgolubev Dec 21 '18 at 09:39
  • @avgolubev You need an interface for the exact same reasons in Guice as in Spring. – chrylis -cautiouslyoptimistic- Sep 26 '19 at 00:46
  • 2
    @chrylis-onstrike- Can u elaborate on reason why I shouldn't inject concrete class directly if I am not going to have different implementation of feature. How having interface help in cases where i don't foresee different implementation in future as well. – pm1090 Feb 04 '20 at 17:05
  • @pm1090 Mocks for unit tests are different implementations that you should have now. – chrylis -cautiouslyoptimistic- Feb 05 '20 at 00:01
  • 1
    @chrylis-onstrike You can test without interfaces, but tearing your code into a bunch of small pieces glued together by a Spring for the test is a stupid thing to do. – avgolubev Mar 31 '20 at 17:25
  • 1
    @avgolubev fully agree, better introduce interfaces only when you need them, in case you want to introduce an alternative implementation and not in advance just for the sake of having an interface. Should be highlighted more in examples that you can autowire implementations directly. Testing is also not an issue when you use tools like Mockito. – Marian Klühspies Nov 19 '20 at 11:36

3 Answers3

273

How does spring know which polymorphic type to use.

As long as there is only a single implementation of the interface and that implementation is annotated with @Component with Spring's component scan enabled, Spring framework can find out the (interface, implementation) pair. If component scan is not enabled, then you have to define the bean explicitly in your application-config.xml (or equivalent spring configuration file).

Do I need @Qualifier or @Resource?

Once you have more than one implementation, then you need to qualify each of them and during auto-wiring, you would need to use the @Qualifier annotation to inject the right implementation, along with @Autowired annotation. If you are using @Resource (J2EE semantics), then you should specify the bean name using the name attribute of this annotation.

Why do we autowire the interface and not the implemented class?

Firstly, it is always a good practice to code to interfaces in general. Secondly, in case of spring, you can inject any implementation at runtime. A typical use case is to inject mock implementation during testing stage.

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

Your bean configuration should look like this:

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

Alternatively, if you enabled component scan on the package where these are present, then you should qualify each class with @Component as follows:

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

Then worker in MyRunner will be injected with an instance of type B.

Vikdor
  • 23,934
  • 10
  • 61
  • 84
  • @stackoverflow Editing the question wouldn't make any sense, new code belongs in the answer. Otherwise the question makes no sense, because it would have answered itself. – Dave Newton Oct 15 '12 at 16:01
  • Vikdor - please see edit. Is that the correct way to annotate the classes and injected object? – stackoverflow Oct 15 '12 at 16:25
  • Is it possible to autowire just IA without qualifier and use the methods provided ? – insomiac Jul 08 '14 at 19:10
  • Instead of using an 'Qualifier' annotation in some cases it is may be preferable to use name of field as sort of qualifier. For example, if you have defined two beans of type A named 'a1' and 'a2' respectively, in your component you can define field '@Autowired A a1;' instead of '@Autowired @Qualifier("a1") a;'. [See reference: 'For a fallback match, the bean name is considered a default qualifier value.'](http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers) – Victor Dombrovsky Aug 05 '15 at 08:10
  • 1
    @VictorDombrovsky Is `@Autowired @Qualifier("a1") a;` valid? – Lucky Sep 29 '16 at 07:23
  • 1
    @Lucky I made a mistake. I meant `@Autowired @Qualifier("a1") A a;` – Victor Dombrovsky Sep 29 '16 at 07:30
  • 2
    if you set the qualifier to "b", then isn't that exactly equivalent to `IA worker=new B();`? why use DI containers at all? to me it seems like you could use constructor based dependency injection and instantiate classes manually – Austin_Anderson Jul 18 '17 at 16:12
  • @Austin_Anderson, Firstly `IA worker = new B()` may not work if B itself has dependencies that need be injected. Secondly, the qualifier need not be defined on the class alone, it can be defined in a spring configuration and the configuration can be different in, let's say prod and test scenarios. Does that make sense? – Vikdor Jul 18 '17 at 17:53
  • I believe your implementing class need not be marked `@Component` only. `@Service` or `@Repository` will work as well. However, use these annotations only when they are meaningful to your class. – Saurabh Tiwari Aug 17 '18 at 07:46
  • 1
    You can even use @Profile on the implementation to control which implementation should be injected for that interface via program arguments or application properties. – b15 Aug 14 '19 at 16:51
1

Also it may cause some warnigs in logs like a Cglib2AopProxy Unable to proxy method. And many other reasons for this are described here Why always have single implementaion interfaces in service and dao layers?

Sergey Ponomarev
  • 2,947
  • 1
  • 33
  • 43
0

It worked for me only when I declared following bean in my .XML configuration file because @Autowired is a post process

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>
Harsh Patel
  • 3
  • 1
  • 3