Java > Spring Framework > Spring Core > Dependency Injection

Constructor Injection in Spring

This example demonstrates dependency injection using the constructor in a Spring-managed bean. Constructor injection ensures that required dependencies are available when the bean is created, promoting immutability and testability.

Code Snippet: Injecting a Service via Constructor

This code defines a MyComponent class that depends on a MyService interface. The @Component annotation marks the class as a Spring-managed bean. The constructor takes an instance of MyService as an argument, and the @Autowired annotation tells Spring to inject the dependency when creating the MyComponent bean.

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {

    private final MyService myService;

    @Autowired
    public MyComponent(MyService myService) {
        this.myService = myService;
    }

    public String doSomething() {
        return "MyComponent is doing something with: " + myService.getData();
    }
}

Code Snippet: Service Interface

This defines the MyService interface that MyComponent depends on.

package com.example;

public interface MyService {
    String getData();
}

Code Snippet: Service Implementation

This provides a concrete implementation of the MyService interface. The @Service annotation marks this class as a service component in Spring.

package com.example;

import org.springframework.stereotype.Service;

@Service
public class MyServiceImpl implements MyService {

    @Override
    public String getData() {
        return "Some data from MyService";
    }
}

Code Snippet: Spring Configuration

This is a simple Spring configuration class. The @Configuration annotation indicates that this class provides Spring configurations. The @ComponentScan annotation tells Spring to scan the com.example package (and subpackages) for components (beans) to manage.

package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.example")
public class AppConfig {

}

Code Snippet: Example Usage

This shows how to retrieve the MyComponent bean from the Spring context and use it. It creates an AnnotationConfigApplicationContext, which loads the configuration from AppConfig. It then retrieves an instance of MyComponent using getBean and calls the doSomething method. Finally, the context is closed.

package com.example;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MyComponent myComponent = context.getBean(MyComponent.class);
        System.out.println(myComponent.doSomething());
        context.close();
    }
}

Concepts Behind Constructor Injection

Constructor injection enforces the availability of dependencies at the time of object creation. This helps in creating immutable objects and allows for easier unit testing because dependencies can be easily mocked or stubbed during testing. Since dependencies are passed via the constructor, the class clearly defines its requirements.

Real-Life Use Case

Imagine a database connection pool manager. It requires a connection factory to create connections. Using constructor injection, you can ensure that the connection pool manager always receives a valid connection factory instance upon initialization, preventing it from starting without the necessary resource.

Best Practices

Use constructor injection for mandatory dependencies. For optional dependencies, consider setter injection. Keep constructors small and focused on dependency injection only. Avoid complex logic inside constructors.

Interview Tip

Be prepared to explain the advantages and disadvantages of constructor injection compared to setter injection. Common advantages are immutability and guaranteed dependency availability. Common disadvantages include potentially long constructor signatures with many dependencies.

When to Use Them

Use constructor injection when dependencies are required for the correct operation of the class. This ensures that the class cannot be instantiated without its dependencies, improving the reliability of the application.

Memory footprint

Constructor injection itself doesn't drastically increase memory footprint. However, injecting a large number of dependencies can lead to a larger object graph in memory. Carefully consider the scope and lifecycle of injected beans to avoid memory leaks or unnecessary object retention.

Alternatives

Setter injection and field injection are the main alternatives to constructor injection. Each has its own pros and cons related to immutability, testability, and code clarity. There is also method injection, but it's less common.

Pros

  • Immutability: Dependencies are assigned once in the constructor and cannot be changed later.
  • Testability: Easy to mock dependencies in unit tests because they are passed through the constructor.
  • Clear Dependencies: The constructor clearly indicates which dependencies are required for the class to function correctly.
  • Guaranteed Dependency Availability: Ensures that all required dependencies are present when the object is created.
  • Cons

  • Constructor Complexity: Constructors can become large and complex if a class has many dependencies.
  • Circular Dependencies: Can lead to circular dependency issues, especially when using constructor injection for all dependencies.
  • Less Flexibility: Changing dependencies requires modifying the constructor, which can be disruptive.
  • FAQ

    • What is the difference between constructor injection and setter injection?

      Constructor injection injects dependencies through the constructor, ensuring they are available when the object is created and promoting immutability. Setter injection injects dependencies through setter methods, allowing for optional dependencies and more flexibility. Constructor injection is generally preferred for mandatory dependencies, while setter injection is suitable for optional dependencies.
    • How does Spring resolve dependencies during constructor injection?

      Spring uses the @Autowired annotation (or the absence of it in the case of a single constructor) to identify which constructor to use for dependency injection. It then looks for beans in the application context that match the types of the constructor parameters. If a matching bean is found, it is injected into the constructor.
    • Can I use constructor injection without the @Autowired annotation?

      Yes, if a class has only one constructor, Spring will automatically use that constructor for dependency injection, even without the @Autowired annotation. However, using @Autowired explicitly is considered good practice for clarity.