Key Takeaways
- Spring autowiring supplies dependencies to objects managed by its application context.
- Prefer constructor injection for required dependencies: it makes collaborators explicit and lets you store them in final fields.
- A single constructor doesn't need @Autowired. The annotation also supports fields and methods, including setters.
- @Autowired is required by default. Use @Qualifier to narrow matching candidates, @Primary to establish a default, and explicit optional-dependency patterns when absence is valid.
Spring autowiring lets the container find a dependency and supply it when creating a managed object. @Autowired identifies injection points, but constructor injection usually needs no annotation when the class has only one constructor.
Autowiring belongs to Spring Framework; Spring Boot adds convenient application setup, component scanning, and auto-configuration. If you're starting from scratch, our Spring Boot tutorial covers the surrounding application structure.
What Is Autowiring in Spring?
A bean is an object managed by Spring's container, usually accessed through an ApplicationContext. Autowiring resolves a bean's dependencies while that bean is being created; it doesn't make every object in your application Spring-managed.
Preface: Dependency Injection in Spring
Dependency injection means supplying a collaborator from outside a class instead of constructing it inside the class. Inversion of control describes the broader shift: the container coordinates object creation rather than each consumer assembling its own dependencies.
Without Dependency Injection
// Standalone illustration; B has no behavior here.
class B {}
class A {
private final B b;
A() {
this.b = new B();
}
}A decides how to construct B. Replacing that collaborator requires changing A.
With Dependency Injection
// Alternative to the preceding illustration.
class B {}
class A {
private final B b;
A(B b) {
this.b = b;
}
}Now the caller chooses the collaborator. This works without Spring; autowiring automates that assembly for managed beans.
Construction inside the consumer:
A constructor --> new B()
Constructor injection with Spring:
Spring --> creates B
Spring --> passes B to A(B)Spring @Autowired: A Runnable Constructor-Injection Example
Generate a Maven/Java project with Spring Initializr, using com.example.autowire as the package and Demo as the name. Choose a stable Spring Boot release and a JDK supported by that release; retain the generated build configuration.
This console example needs only the core spring-boot-starter dependency, not a web starter. In the generated Boot-managed pom.xml, ensure this dependency is present:
<!-- Fragment inside the generated pom.xml's dependencies element. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>Replace the generated application file at src/main/java/com/example/autowire/DemoApplication.java with the following. The package-private helper types share one file to keep the example small.
package com.example.autowire;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
try (ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args)) {
A a = context.getBean(A.class);
System.out.println(a.getB().message());
}
}
}
interface B {
String message();
}
@Component
class DefaultB implements B {
@Override
public String message() {
return "B injected";
}
}
@Component
class A {
private final B b;
public A(B b) {
this.b = b;
}
public B getB() {
return b;
}
}Run DemoApplication.main in your IDE, or use the generated Maven wrapper from the project directory. The Spring Boot Maven plugin's run goal compiles and runs the application.
./mvnw spring-boot:runThe application prints B injected after startup logging, then closes its context. Component scanning discovers A and DefaultB; Spring finds one candidate for B and passes it to A's constructor.
Dependency Injection Without Autowiring
You can assemble the relationship explicitly instead. For this alternative, remove @Component from A and DefaultB, keep their other code, and save this as ManualConfig.java in the same package. Run ManualConfig.main from your IDE.
package com.example.autowire;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ManualConfig {
@Bean
public B b() {
return new DefaultB();
}
@Bean
public A a() {
return new A(b());
}
public static void main(String[] args) {
try (var context =
new AnnotationConfigApplicationContext(ManualConfig.class)) {
System.out.println(context.getBean(A.class).getB().message());
}
}
}Both objects are registered through @Bean methods, and the configuration explicitly chooses which collaborator to pass. In this full @Configuration class, Spring intercepts the call to b() so it returns the managed bean. Don't change it to @Configuration(proxyBeanMethods = false) while relying on that interception; see Spring's inter-bean configuration rules.
Constructors, Setters, and Fields: Which Should You Use?
@Autowired supports constructors, fields, and methods; setters are one kind of supported method. Calling field injection “property injection” obscures the actual Java injection point.
| Injection style | When it fits | Main trade-off |
|---|---|---|
| Constructor | Required collaborators; the usual application-code default | Dependencies are explicit and references can be final |
| Setter or configuration method | Optional collaborators with a sensible default | The collaborator is assigned after construction and remains mutable |
| Field | Recognizing existing code; generally avoid for application services | Dependencies are hidden from callers and plain unit tests |
@Autowired on Constructors
Constructor injection makes required dependencies visible in the class's API and supplies them before construction completes. A final field prevents reassignment of that reference; it doesn't make the referenced object immutable. Spring's documentation recommends constructor injection for required dependencies.
You may annotate the constructor explicitly:
// Fragment replacing A's constructor; add this import to its file.
import org.springframework.beans.factory.annotation.Autowired;
// Inside class A:
@Autowired
public A(B b) {
this.b = b;
}The original runnable example is also easy to exercise without a container: construct A with a test implementation of B. That's one practical reason to prefer this style; our article on the benefits of unit testing explains the larger payoff.
@Autowired on Setter Methods
A setter is useful when the object has a valid default collaborator. Autowired setters run after construction; an ordinary @Autowired setter is still required unless you change its optionality.
// Alternative component fragment in com.example.autowire; reuses B.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
class SetterA {
private B b = () -> "fallback";
@Autowired(required = false)
public void setB(B b) {
this.b = b;
}
public B getB() {
return b;
}
}If no matching B exists, Spring skips this setter and leaves the fallback intact. A non-required field similarly retains its existing value when no candidate is available. Setter injection also permits later reassignment, so use it deliberately rather than treating mutability as an automatic benefit.
@Autowired on Fields
// Field-injection fragment; generally avoid in application services.
import org.springframework.beans.factory.annotation.Autowired;
// Inside a Spring-managed class:
@Autowired
private B b;
public B getB() {
return b;
}Spring populates an autowired field after constructing the object, even when the field is private. The constructor doesn't reveal the dependency, and a plain unit test can't supply it through construction. Prefer the constructor-based A above.
Optional Dependencies Without Mutable Setters
Optional<B> can express an optional constructor dependency. Keep this as an alternative design, not a workaround for a bean that should be registered but isn't.
// Alternative component fragment in com.example.autowire; reuses B.
import java.util.Optional;
import org.springframework.stereotype.Component;
@Component
class OptionalA {
private final Optional<B> b;
public OptionalA(Optional<B> b) {
this.b = b;
}
public String message() {
return b.map(B::message).orElse("fallback");
}
}For deferred lookup, inject ObjectProvider<B> instead. Its getIfAvailable() method returns null when no candidate exists, but still throws NoUniqueBeanDefinitionException when multiple candidates remain without a unique winner. Spring also supports nullable injection points when null is the intended contract.
Resolve Multiple Beans with @Qualifier and @Primary
Suppose both Square and Triangle implement Shape. @Primary gives one candidate preference for a single-valued dependency; @Qualifier narrows the candidates at a particular injection point.
Using the component-scanned Boot example, add this file as Shapes.java in the same package:
package com.example.autowire;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
interface Shape {
int getCorners();
}
@Component("square")
@Primary
class Square implements Shape {
@Override
public int getCorners() {
return 4;
}
}
@Component("triangle")
class Triangle implements Shape {
@Override
public int getCorners() {
return 3;
}
}
@Component
class ShapeService {
private final Shape defaultShape;
private final Shape selectedShape;
public ShapeService(Shape defaultShape,
@Qualifier("triangle") Shape selectedShape) {
this.defaultShape = defaultShape;
this.selectedShape = selectedShape;
}
public int defaultCorners() {
return defaultShape.getCorners();
}
public int selectedCorners() {
return selectedShape.getCorners();
}
}Add these calls inside DemoApplication's existing try block:
// Fragment inside the existing application-context block.
ShapeService shapes = context.getBean(ShapeService.class);
System.out.println(shapes.defaultCorners()); // 4: @Primary Square
System.out.println(shapes.selectedCorners()); // 3: qualified TriangleThe qualifier narrows eligible Shape beans to the triangle candidate, so the primary square isn't selected for that parameter. Here, triangle matches a bean name, but qualifiers can also represent matching metadata; they're not restricted to bean-name lookup. A qualifier still needs a compatible type.
Without the qualifier or another selection rule, multiple eligible beans can leave a single-valued dependency ambiguous. Use our Spring @Qualifier example for another focused walkthrough.
Autowire in Spring Boot Not Working?
Check Registration and the Scan Boundary
@SpringBootApplication combines @SpringBootConfiguration, @EnableAutoConfiguration, and @ComponentScan. Its default component scan covers the application class's package and subpackages—not unrelated packages.
com.example.autowire
DemoApplication.java application class
service/A.java inside the default scan
dependency/DefaultB.java inside the default scan
com.example.shared
ExternalClient.java outside the default scanMove the application class above your components, explicitly configure scanning, or register the missing dependency through configuration. Component annotations aren't the only registration route: @Bean methods work too. Beans from separate configuration classes can collaborate when those configurations are loaded into the same application context.
Distinguish Missing Beans from Ambiguous Beans
@Autowired is required by default. A missing required candidate prevents creation of the dependent bean, typically surfacing as an UnsatisfiedDependencyException with an underlying NoSuchBeanDefinitionException. For eagerly created beans, that prevents application startup.
- No qualifying bean: check the requested type, bean registration, scan package, and any qualifier.
- Multiple candidates: narrow the injection point with
@Qualifieror establish one suitable default with@Primary. - Optional dependency: define the intended fallback behavior; don't make a mandatory dependency optional just to suppress a startup failure.
Check Who Created the Consumer
Calling new yourself doesn't automatically trigger Spring field or setter injection. Retrieve the managed consumer from the context or supply its collaborators yourself through its constructor; merely annotating the class isn't enough to manage an arbitrary instance.
FAQ
Is @Autowired required on a single constructor in Spring?
No. Since Spring Framework 4.3, Spring can use a bean class's single constructor without @Autowired. Its required collaborators must still be resolvable from the application context.
Should I use constructor injection or field injection in Spring?
Prefer constructor injection for required dependencies. It exposes collaborators to callers, supports final references, and lets unit tests construct the object without Spring; field injection hides dependencies and requires separate population after construction.
How do I choose between multiple beans of the same type?
Use @Qualifier on the injection point to narrow eligible beans, or mark one candidate @Primary to make it the default for single-valued injection. A qualifier can match a bean name, but it can also match qualifier metadata.
Why does Spring say no qualifying bean is available?
The container couldn't find an eligible bean for the requested dependency. Check its type, registration through component scanning or @Bean, the scan-package boundary, and any qualifier that might exclude it.
Can Spring autowire an object created with new?
Not automatically. An instance you create directly doesn't receive Spring's normal field or setter injection; use a managed bean or pass its dependencies through the constructor yourself.
Further Reading
- Using @Autowired — injection points, required dependencies, and optional forms.
- Spring dependency injection — constructor and setter trade-offs and bean creation.
- Autowiring with qualifiers — type matching and qualifier metadata.
- Selecting a primary candidate — preference when multiple beans match.
- Structuring Spring Boot code — application packages and scan boundaries.
- Java configuration and inter-bean dependencies — explicit wiring with @Configuration.
- ObjectProvider API — deferred and optional dependency lookup.
