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
Cons
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.