Using @Autowired
The @Autowired annotation is a powerful tool for dependency injection in Spring. It tells Spring to automatically inject an object into another object. This process is also known as "wiring."
Example :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CarService {
@Autowired
private EngineService engineService;
public void startCar() {
engineService.startEngine();
}
}
In this example, we have a CarService class that depends on an EngineService. By adding @Autowired above the EngineService field, we're telling Spring to automatically find an EngineService bean & inject it into this class.
You can use @Autowired in three different ways:
-
Field injection (as shown in the example above)
-
Constructor injection
- Setter injection
We'll cover these in more detail in later sections.
It's important to note that for @Autowired to work, both the class being autowired (CarService in this case) & the dependency (EngineService) need to be Spring beans. This means they should be annotated with @Component or one of its specialized annotations (@Service, @Repository, @Controller).
If Spring finds multiple beans of the same type, it will throw an exception. To solve this, you can use the @Qualifier annotation to specify which bean you want to inject.
@Autowired
@Qualifier("dieselEngine")
private EngineService engineService;
This tells Spring to inject the EngineService bean with the qualifier "dieselEngine".
Using @Autowired can significantly reduce the amount of configuration code you need to write, making your application easier to maintain & understand.
XML Configuration file
While Java-based configuration is becoming more popular, XML configuration is still widely used in many Spring projects. Here's how you can set up @Autowired using XML configuration:
First, you need to create an XML configuration file, typically named applicationContext.xml.
This file should be placed in your project's resources folder. Here's a basic structure:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Enable annotation-based configuration -->
<context:annotation-config/>
<!-- Define your beans here -->
<bean id="engineService" class="com.example.EngineService"/>
<bean id="carService" class="com.example.CarService"/>
</beans>
In this XML file:
-
We declare the necessary XML namespaces & schema locations.
-
We enable annotation-based configuration with <context:annotation-config/>.
- We define our beans using the <bean> tags.
With this configuration, Spring will create instances of EngineService & CarService. If CarService has an @Autowired annotation for EngineService, Spring will automatically inject the EngineService bean into CarService.
To use this XML configuration in your Java code, you need to load it:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
CarService carService = context.getBean(CarService.class);
carService.startCar();
context.close();
}
}
This code loads the XML configuration, retrieves the CarService bean, & uses it.
XML configuration can be particularly useful when working with third-party libraries or when you need to configure a large number of beans. However, for most modern Spring applications, Java-based configuration is often preferred due to its type safety & refactoring friendliness.
Java Configuration class
Java Configuration is a modern alternative to XML configuration in Spring. It uses Java classes & annotations to configure the Spring container. Here's how you can set up @Autowired using Java Configuration:
First, create a configuration class:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
@Bean
public EngineService engineService() {
return new EngineService();
}
@Bean
public CarService carService() {
return new CarService();
}
}
In this Java Configuration class:
-
We use @Configuration to mark this class as a source of bean definitions.
-
@ComponentScan tells Spring to look for other components, configurations, & services in the "com.example" package.
- We define beans using @Bean methods. Each method creates & returns an instance of a bean.
With this setup, Spring will create instances of EngineService & CarService. If CarService has an @Autowired annotation for EngineService, Spring will automatically inject the EngineService bean into CarService.
To use this Java Configuration in your code:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CarService carService = context.getBean(CarService.class);
carService.startCar();
context.close();
}
}
This code loads the Java Configuration, retrieves the CarService bean, & uses it.
Java Configuration offers several advantages:
-
Type safety: Misspellings & type mismatches are caught at compile time.
-
Better for refactoring: IDEs can help with renaming & moving classes.
- Easier testing: You can create different configurations for different environments.
Remember, you can mix Java Configuration & XML Configuration if needed. This flexibility allows you to choose the best approach for each part of your application.
Constructor based Autowiring
Constructor based autowiring is a method where Spring injects dependencies through a class's constructor. This approach is often preferred because it promotes immutability & ensures that a bean is always in a valid state after construction.
Here's how you can use constructor-based autowiring:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CarService {
private final EngineService engineService;
private final WheelService wheelService;
@Autowired
public CarService(EngineService engineService, WheelService wheelService) {
this.engineService = engineService;
this.wheelService = wheelService;
}
public void startCar() {
engineService.start();
wheelService.inflate();
System.out.println("Car is ready to go!");
}
}
In this example:
-
We have a CarService class that depends on EngineService & WheelService.
-
We define a constructor that takes these dependencies as parameters.
- We mark the constructor with @Autowired (though this is optional in newer Spring versions if the class has only one constructor).
When Spring creates an instance of CarService, it will:
-
Identify the constructor to use for dependency injection.
-
Locate beans of type EngineService & WheelService.
- Pass these beans as arguments when calling the constructor.
Constructor injection has several benefits:
-
It ensures that required dependencies are not null (unless explicitly passed as null).
-
It supports immutability, as dependencies can be declared as final fields.
- It prevents the class from being constructed without its dependencies.
If you have multiple constructors, you can specify which one Spring should use for autowiring:
@Service
public class CarService {
private final EngineService engineService;
private final WheelService wheelService;
@Autowired
public CarService(EngineService engineService, WheelService wheelService) {
this.engineService = engineService;
this.wheelService = wheelService;
}
public CarService(EngineService engineService) {
this(engineService, new DefaultWheelService());
}
}
In this case, Spring will use the constructor marked with @Autowired.
Constructor-based autowiring is generally considered the best practice in modern Spring applications, as it makes dependencies explicit & supports writing more testable code.
Property-based Autowiring
Property-based autowiring, also known as field injection, is a simple way to inject dependencies directly into fields of a class.
Here's how it works:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CarService {
@Autowired
private EngineService engineService;
@Autowired
private WheelService wheelService;
public void startCar() {
engineService.start();
wheelService.inflate();
System.out.println("Car is ready to go!");
}
}
In this example:
-
We declare private fields for our dependencies (EngineService & WheelService).
-
We add the @Autowired annotation directly above each field.
- Spring will inject the appropriate beans into these fields when creating the CarService instance.
Property-based autowiring is straightforward to use & requires minimal code. However, it has some disadvantages also:
-
It makes unit testing harder because you can't easily inject mock objects for testing.
-
It doesn't allow for final fields, which means you can't ensure immutability.
- It can make it unclear which dependencies are required for the class to function properly.
You can also use @Autowired with private fields in non-Spring-managed classes, but you'll need to perform extra steps to process the annotations:
public class NonSpringManagedClass {
@Autowired
private SomeService someService;
public NonSpringManagedClass() {
AutowireCapableBeanFactory factory = springContext.getAutowireCapableBeanFactory();
factory.autowireBean(this);
}
}
In this case, you need to manually invoke the autowiring process using AutowireCapableBeanFactory.
While property-based autowiring is convenient, many developers prefer constructor injection or setter injection for their improved testability & clarity. However, in scenarios where you have many optional dependencies, property-based injection can still be a useful tool.
Setter based Autowiring
Setter-based autowiring is another method of dependency injection in Spring. In this approach, Spring uses setter methods to inject dependencies into a bean.
Here's how it works:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CarService {
private EngineService engineService;
private WheelService wheelService;
@Autowired
public void setEngineService(EngineService engineService) {
this.engineService = engineService;
}
@Autowired
public void setWheelService(WheelService wheelService) {
this.wheelService = wheelService;
}
public void startCar() {
engineService.start();
wheelService.inflate();
System.out.println("Car is ready to go!");
}
}
In this example:
-
We declare private fields for our dependencies (EngineService & WheelService).
-
We create setter methods for each dependency.
-
We add the @Autowired annotation above each setter method.
When Spring creates the CarService bean, it will:
-
Instantiate the CarService class.
-
Call the setter methods to inject the dependencies.
Setter injection has some advantages:
-
It allows for optional dependencies. If a setter method isn't called, the dependency remains null.
-
It enables you to re-inject dependencies after the bean is created.
However, it also has disadvantages:
-
It doesn't ensure that a dependency will be injected (unlike constructor injection).
-
It can't be used with final fields, so you can't ensure immutability.
You can also use @Autowired on methods with arbitrary names & multiple arguments:
@Autowired
public void setupServices(EngineService engineService, WheelService wheelService) {
this.engineService = engineService;
this.wheelService = wheelService;
}
Spring will call this method & provide all the necessary dependencies.
Setter injection is useful when you have optional dependencies or when you need to change dependencies at runtime. However, for required dependencies, constructor injection is often preferred as it ensures the bean is always in a valid state after construction.
Optional Dependencies
In Spring, not all dependencies are always required. Sometimes, you might want to inject a dependency only if it's available. This is where optional dependencies come into play.
Here's how you can work with optional dependencies using @Autowired:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CarService {
private EngineService engineService;
private WheelService wheelService;
private OptionalGPSService gpsService;
@Autowired
public CarService(EngineService engineService, WheelService wheelService) {
this.engineService = engineService;
this.wheelService = wheelService;
}
@Autowired(required = false)
public void setGPSService(OptionalGPSService gpsService) {
this.gpsService = gpsService;
}
public void startCar() {
engineService.start();
wheelService.inflate();
if (gpsService != null) {
gpsService.initializeGPS();
}
System.out.println("Car is ready to go!");
}
}
In this example:
-
We have required dependencies (EngineService & WheelService) injected through the constructor.
-
We have an optional dependency (OptionalGPSService) injected through a setter method.
-
We use @Autowired(required = false) for the optional dependency.
- If Spring can't find a bean of type OptionalGPSService, it simply won't call the setGPSService method, & gpsService will remain null.
You can also use Java 8's Optional for field injection of optional dependencies:
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
public class CarService {
@Autowired
private Optional<OptionalGPSService> gpsService;
public void useGPS() {
gpsService.ifPresent(OptionalGPSService::initializeGPS);
}
}
In this case, gpsService will always be a non-null Optional, but it might be empty if no OptionalGPSService bean is available.
Another way to handle optional dependencies is by using @Nullable:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
public class CarService {
private OptionalGPSService gpsService;
@Autowired
public void setGPSService(@Nullable OptionalGPSService gpsService) {
this.gpsService = gpsService;
}
}
Here, Spring will always call setGPSService, but it might pass null if no OptionalGPSService bean is found.
Using optional dependencies allows your application to be more flexible. It can adapt to different configurations & environments where certain services might or might not be available.
Frequently Asked Questions
What is the use of @autowired annotation?
The @Autowired annotation is used in Spring to automatically inject dependencies, allowing Spring to manage object creation and wiring.
What is the difference between @bean and @autowired?
@Bean defines a method that produces a Spring-managed bean, while @Autowired injects dependencies into a class, linking required beans automatically.
What is the benefit of Autowired in Spring?
@Autowired reduces boilerplate code, promotes loose coupling, and simplifies dependency management by letting Spring handle object creation and injection.
Conclusion
In this article, we have learned about the Spring @Autowired annotation. We explained how to enable & use @Autowired, explored XML & Java-based configurations, & discussed different types of autowiring including constructor-based, property-based, & setter-based. We also looked at handling optional dependencies. @Autowired is a powerful tool that simplifies dependency injection in Spring applications, making them more modular & easier to maintain.
You can refer to our guided paths on Code 360. You can check our course to learn more about DSA, DBMS, Competitive Programming, Python, Java, JavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithms, Competitive Programming, Operating Systems, Computer Networks, DBMS, System Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry.