0

I am new to Spring so my understanding of it is very superficial, nevertheless, suppose we are looking at the following example:

class serviceImpl implements service{
    @Autowired
    private Mapper mapper;
    public void executeService(){
        mapper.executeSerice();
    }
}

So, I am trying to build some service, which calls mapper from the persistence level. Mapper is an abstract class. So from my understanding, @Autowired will automatically injects one implementation of Mapper here.

Then my question is:

  1. What if there are multiple implementations of Mapper? After some search, it seems that in this case one needs to use @Qualifier to designate which implementation we want to use.

  2. Suppose we are using the implementation powerfulMapper, then we will need to use @Qualifier('powerfulMapper').

Then how is this different from just instantiating Mapper powerfulMapper here?

2
  • Generally you decide on the implementation from outside, e.g. injecting a test double for unit tests. If you're over-qualifying your deps like that DI isn't so valuable. It seems like you're just asking what DI is for, rather than why use the annotation.
    – jonrsharpe
    Commented Jun 7, 2020 at 18:14
  • Thank you for answering, and can you maybe expand your first sentence in more details? I do not quire understand what ”form outside“ means.
    – z.z
    Commented Jun 7, 2020 at 18:28

3 Answers 3

1

If you have only one Mapper , you only need @Autowired to inject. If there are more than one Mapper implementation registered as Spring bean , you have to use @Qualifier or @Resource to tell Spring which implementation you want to inject. See this for more details.

Then how is this different from just instantiating Mapper powerfulMapper here?

The difference is that if a class is a Spring bean , we can apply some Spring feature on it such as :

  • Apply some AOP magic on it such as @Async , @Transactional , @PreAuthorize etc.

  • Think about the case that if a class has a lot of dependencies which in turn has a lot of dependencies, creating an instance of this class configuring with the whole dependency graph is not an enjoyable thing to do . Not to mention different dependency can has different requirements (e.g. one may needed to be instantiated as a singleton and will be shared to be used by different class while other may need to be in the prototype scope which different classes need a separate instance etc.)

Using @Autowired and let spring to configure such dependency graph is more easier than do it manually.

On the other hands , if the Mapper has very simple dependencies , only used internally inside ServiceImpl and you don't need any benefit provided by spring on it , you can simply instantiate it without declaring it as spring bean.

3
  • Thank you very much for you answer, but what do you mean by configuring with the whole dependency graph?
    – z.z
    Commented Jun 7, 2020 at 20:22
  • It means in order to create an object (e.g Mapper) that has some mandatory dependencies (e.g ClassA), you have to instantiate ClassA first. So if ClassA has other mandatory dependencies (e.g Class B), you have to create ClassB first before you can create ClassA , and if ClassB has other dependencies ClassC , you have to create ClassC before create ClassB and so on....... These dependencies is just a graph if you put some imagination on it.
    – Ken Chan
    Commented Jun 8, 2020 at 4:40
  • but say A depends on B, B depends on C, the dependency of B on C is already built in B, when I create A, it does not seem to me that I need to worry about that dependency. Also even if I use dependency injection, If I ever change the functions in the interface C, it still seems to me that I need to go revise everything that uses C.
    – z.z
    Commented Jun 8, 2020 at 16:39
1

Dependency Injection (DI) is so that you avoid having a complicated tree of dependencies.

Imagen having a tree like structure where A instantiates class B and class B instantiates class C, then A instantiates D and D instantiates E.

A --> B ---> C
 \
  \--> D ---> E

This is all fine fine, until class E needs class C.

Then we need to re arrange everything and instantiate C higher up and pass it through class B and D down to both sides.

This is where DI comes into play.

We instead decide that A instantiates all classes

A --> B
  --> C
  --> D
  --> E

So A is the owner of all classes, and he can then pass in any class to any class to meet whatever demand any class has.

This is what the Spring context does with the help of the @Autowire annotation. You declare for spring what class you want to be passed in the instantiated classes. Then Spring during startup, will instantiate all classes and then figure out what class should be fitted where (this is massive simplification). All classes will per default be instantiated as singletons (but this can be customised).

When spring instantiates you class it is called a spring managed bean. Spring manages the lifecycle of it. Not you, because you are not using new, the framework is.

During this process Spring does a number of checks and also instantiates in a specific order, configuration classes first, then @Bean annotated classes, and lastly @Component, @Service etc (overly simplifying this here), it will scan for what classes that should be instantiated, it will decide upon an order in which should be instantiated first, then which classes should be @Autowired into which classes. There are a number of help annotations that will assist Spring during this phase.

@Qualifier is one, you basically name a class, then you can tell spring where you want it @Autowired.

It's very useful if you have two singletons configured differently but they have the same name.

0

As you said, if you want different implementations you need to use @Qualifier("powerfulMapper") etc.

Lets suppose you have two different implementations one use @Qualifier("powerfulMapper") and the other is @Qualifier("notAPowerfulMapper").

Then while you autowire you also need to specify which one you need to inject like

@Autowired
@Qualifier("powerfulMapper")
private Mapper mapper;

Not the answer you're looking for? Browse other questions tagged or ask your own question.