klippy
klippy

Reputation: 243

What is the purpose for marking an injection constructor with an @Autowired attribute?

I am trying to wrap my head around the @Autowired annotation. I have read into it, but it still isn't making much sense to me

The specific case I'm looking for at is passing a repository into a micro service class

Why do we do

@Autowired
public SomeClass (Repo repo) {
    this.repo = repo;
}

instead of simply doing

public SomeClass (Repo repo) {
    this.repo = repo;
}

Upvotes: 1

Views: 922

Answers (4)

Steven
Steven

Reputation: 172616

You are right. DI Containers, like Spring, are meant to decouple components from one another, by adhering to the Dependency Inversion Principle (DIP). From that perspective, it is rather awkward—to say the least—when your DI Container forces you to apply those library-specific attributes to your classes. This again introduces tight coupling—the thing we are working so hard to prevent. It also forces a vendor lock-in. All your application code now depends on this external tool. This is a violation of the DIP.

Instead, when your application components have a single public constructor, which is a good practice, there should be no need to define any such attribute on the class. In that case, the class's constructor unambiguously declares its required dependencies. Any good DI Container should be able to compose an object graph based on the static type information provided by that single constructor.

If I'm not mistaken, newer versions of Spring do allow you to ommit the attribute.

Upvotes: 1

user5199849
user5199849

Reputation:

The @Autowired annotation will automatically use a 'Bean' (spring-managed resource) of type Repo from the application context if one exists. If your SomeClass method is itself a 'Bean' (annotated with @Component, @Service, or @Repository), spring will ensure that a bean of type Repo exists in the application context before instantiating your SomeClass bean.

This article is helpful: https://www.baeldung.com/spring-autowire

As others on this thread have mentioned, constructor injection makes unit testing easier. One way to get around this is to create a static class annotated with @TestConfiguration that contains the beans you need for your test context.

This article has some info about that: https://www.baeldung.com/spring-boot-testing

The Baeldung site is a great resource if you are new to spring.

Upvotes: 0

akuma8
akuma8

Reputation: 4681

You can do this:

public SomeClass (Repo repo) {
    this.repo = repo;
}

if you plan to instantiate your object yourself. But since you want the container to instantiate your objects (beans), you instruct it to inject your Repo dependency during SomeClass bean creation. You do that by adding @Autowired on top of your constructor.

You could also do this (field injection):

@Component
public class SomeClass {
    @Autowired
    private Repo repo;
} 

But to make unit testing easier, constructor injection is preferable. Note that since Spring 4.3 @Autowired is no longer necessary on the constructor.

EDIT

Better, when using Lombok you can do this:

@Component
@RequiredArgConstructor
public class SomeClass {

    private final Repo repo;
}

Lombok will generate the constructor

public SomeClass (Repo repo) {
    this.repo = repo;
}

for you and the container will inject the dependency.

Upvotes: 1

Oreste Viron
Oreste Viron

Reputation: 3805

When you have multiple constructor, you must indicate to spring which constructor to use. Useless much of the time.

Check here : https://www.baeldung.com/constructor-injection-in-spring

As of Spring 4.3, classes with a single constructor can omit the @Autowired annotation. A nice little bit of convenience and boilerplate removal!

Upvotes: 0

Related Questions