Definition
- @Autowired -- Spring's injection annotation that resolves by TYPE first, uses
@Qualifieror field name as tiebreaker, supportsrequired=false, works on constructors, fields, and setters. - @Resource -- Jakarta JSR-250 annotation that resolves by NAME first (the
nameattribute or field name), falls back to type, works only on fields and setters (not constructors). - @Inject -- Jakarta CDI annotation that resolves by TYPE like
@Autowired, uses@Namedinstead of@Qualifier, has norequired=falsesupport. - No annotation -- the modern default: a single constructor is auto-detected by Spring 4.3+ with no annotation needed.
@Autowired is like telling the National Bank of India branch manager: "I need A printer" (by type, any model will do). @Resource(name="laserPrinter") is like saying: "I need THE laser printer on the second floor" (by name, specific unit). @Inject is the same request as @Autowired but written on a standard Jakarta form. The best approach: just have ONE desk setup procedure (single constructor) and the manager handles everything without any forms.
Understanding the Concepts
What is the resolution order for each annotation?
Each injection annotation resolves bean ambiguity in a different order:
| Step | @Autowired (Spring) | @Resource (Jakarta) | @Inject (CDI) |
|---|---|---|---|
| 1st | Type match | name attribute | Type match |
| 2nd | @Qualifier | Field/property name | @Named |
| 3rd | Field/parameter name | Type fallback | Field/parameter name |
| 4th | @Primary | Exception | Exception |
| 5th | Exception | | |
package com.bank.service;
import com.bank.repository.AccountRepository;
import jakarta.annotation.Resource;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
// @Autowired: TYPE first, then @Qualifier
public class ServiceA {
@Autowired
@Qualifier("jpaAccountRepository")
private AccountRepository repo;
}
// @Resource: NAME first, then type
public class ServiceB {
@Resource(name = "jpaAccountRepository")
private AccountRepository repo;
}
// @Inject: TYPE first, then @Named
public class ServiceC {
@Inject
@Named("jpaAccountRepository")
private AccountRepository repo;
}
All three examples inject the same bean, but the resolution strategy differs. @Autowired starts from the type and narrows by qualifier. @Resource starts from the name and falls back to type. @Inject behaves like @Autowired but uses @Named instead of @Qualifier.
Why can @Resource NOT do constructor injection?
The @Resource annotation's @Target includes TYPE, FIELD, and METHOD but does not include PARAMETER. Constructor injection works by annotating constructor parameters, which requires ElementType.PARAMETER in the target. Since @Resource lacks this, the compiler rejects it on constructor parameters.
package com.bank.service;
import com.bank.repository.AccountRepository;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class TransferService {
// WRONG -- does not compile
// public TransferService(@Resource(name = "jpaRepo") AccountRepository repo) { }
// ^^^^^^^^^ @Resource not applicable to PARAMETER
// @Resource works on fields and setters only
@Resource(name = "jpaAccountRepository")
private AccountRepository repo;
}
This is a significant limitation because constructor injection is the recommended style. Use @Autowired with @Qualifier on constructor parameters when you need name-based resolution:
package com.bank.service;
import com.bank.repository.AccountRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class TransferService {
private final AccountRepository repo;
// CORRECT -- @Qualifier on constructor parameter
public TransferService(
@Qualifier("jpaAccountRepository") AccountRepository repo) {
this.repo = repo;
}
}
How do you do DI without any annotation?
Since Spring 4.3, a class with a single constructor does not need @Autowired. Spring auto-detects it and resolves all parameters from the container. Combined with Lombok, this is the cleanest style:
package com.bank.service;
import com.bank.repository.AccountRepository;
import com.bank.repository.AuditRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
@Service
@RequiredArgsConstructor
public class TransferService {
private final AccountRepository accountRepo;
private final AuditRepository auditRepo;
// No @Autowired, no @Inject, no @Resource
// Lombok generates the constructor, Spring auto-detects it
@Transactional
public void transfer(String from, String to, BigDecimal amount) {
var sender = accountRepo.findById(from).orElseThrow();
var receiver = accountRepo.findById(to).orElseThrow();
sender.debit(amount);
receiver.credit(amount);
accountRepo.save(sender);
accountRepo.save(receiver);
auditRepo.log(from, to, amount);
}
}
Transfer completed: SAV2001 -> SAV2002, amount=10000
Audit logged: SAV2001 -> SAV2002, amount=10000
How is @Autowired different from @Resource and @Inject?
| Feature | @Autowired | @Resource | @Inject |
|---|---|---|---|
| Package | org.springframework.beans.factory.annotation | jakarta.annotation | jakarta.inject |
| Standard | Spring proprietary | Jakarta JSR-250 | Jakarta CDI (JSR-330) |
| Resolution | Type first | Name first | Type first |
| Disambiguation | @Qualifier | name attribute | @Named |
| Optional deps | required = false | No | No |
| Constructor | Yes | No (missing PARAMETER target) | Yes |
| Field | Yes | Yes | Yes |
| Setter | Yes | Yes | Yes |
| Spring coupling | Yes | No | No |
package com.bank.service;
import com.bank.repository.AccountRepository;
import jakarta.annotation.Resource;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
// All three inject the same bean differently:
@Service
public class AutowiredExample {
@Autowired
@Qualifier("jpaAccountRepository")
private AccountRepository repo;
}
@Service
public class ResourceExample {
@Resource(name = "jpaAccountRepository")
private AccountRepository repo;
}
@Service
public class InjectExample {
@Inject
@Named("jpaAccountRepository")
private AccountRepository repo;
}
When should you use each annotation?
- No annotation (single constructor): the modern default and cleanest approach. Use this for all new code.
- @Autowired: when you need
required = falsefor optional dependencies, or when a class has multiple constructors and you need to tell Spring which one to use. - @Resource: for legacy Java EE interoperability where name-based resolution is needed. Avoid for new code because it cannot do constructor injection.
- @Inject: for Jakarta CDI compatibility in mixed CDI and Spring codebases. Rarely needed in Spring Boot applications.
package com.bank.service;
import com.bank.repository.AccountRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ReportService {
private final AccountRepository accountRepo;
private NotificationService notificationService; // optional
public ReportService(AccountRepository accountRepo) {
this.accountRepo = accountRepo;
}
@Autowired(required = false) // only @Autowired supports this
public void setNotificationService(NotificationService notificationService) {
this.notificationService = notificationService;
}
public void generateReport(String accountId) {
var account = accountRepo.findById(accountId).orElseThrow();
String report = "Balance: " + account.getBalance();
if (notificationService != null) {
notificationService.send(accountId, report);
}
}
}
What are common mistakes with injection annotations?
WRONG -- using @Resource on a constructor parameter:
package com.bank.service;
import com.bank.repository.AccountRepository;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class TransferService {
private final AccountRepository repo;
// WRONG -- does not compile
// @Resource cannot target PARAMETER
public TransferService(@Resource AccountRepository repo) {
this.repo = repo;
}
}
error: annotation @Resource is not applicable in this context
CORRECT -- use @Qualifier with constructor injection:
package com.bank.service;
import com.bank.repository.AccountRepository;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class TransferService {
private final AccountRepository repo;
public TransferService(
@Qualifier("jpaAccountRepository") AccountRepository repo) {
this.repo = repo;
}
}
WRONG -- mixing @Inject and @Qualifier:
// @Inject uses @Named, not @Qualifier
@Inject
@Qualifier("smsService") // Spring-specific, not CDI standard
private NotificationService notification;
CORRECT -- @Inject with @Named:
@Inject
@Named("smsNotificationService") // CDI standard
private NotificationService notification;
What should a senior engineer know?
- Spring processes @Autowired, @Resource, and @Inject through different BeanPostProcessors.
AutowiredAnnotationBeanPostProcessorhandles@Autowiredand@Inject.CommonAnnotationBeanPostProcessorhandles@Resource. - @Resource name resolution includes JNDI lookup in Java EE containers, making it useful for JNDI-bound DataSources in legacy application servers.
- In Spring Boot 3, jakarta.inject replaces javax.inject. If upgrading from Spring Boot 2.x, update the import from
javax.inject.Injecttojakarta.inject.Inject. - GraalVM native images work best with constructor injection because it avoids reflection. Field injection with
@Autowiredrequires reflection hints inreflect-config.json. - The modern trend is no annotation at all. The Spring team recommends single-constructor, no-annotation injection with Lombok
@RequiredArgsConstructor. This is the dominant style in production Spring Boot applications.
What are common interview follow-up questions?
- What is the resolution order of
@Autowired? (Type, @Qualifier, field name, @Primary, exception.) - Can
@Resourcedo constructor injection? (No, its @Target lacks PARAMETER.) - What is the difference between
@Qualifierand@Named? (@Qualifier is Spring, @Named is CDI; both serve the same purpose.) - When do you actually need
@Autowired? (Multiple constructors,required=falsefor optional deps.) - Which BeanPostProcessor handles
@Resource? (CommonAnnotationBeanPostProcessor.)
Visual Overview
@Autowired resolution:
TYPE → @Qualifier → field name → @Primary → Exception
@Resource resolution:
name attribute → field name → TYPE fallback → Exception
@Inject resolution:
TYPE → @Named → field name → Exception
┌──────────────────────────────────────────────┐
│ Modern Recommendation: │
│ │
│ @Service │
│ @RequiredArgsConstructor │
│ public class TransferService { │
│ private final AccountRepository repo; │
│ private final AuditRepository audit; │
│ // No annotation needed! │
│ } │
└──────────────────────────────────────────────┘
Key Takeaway
The three injection annotations differ in resolution strategy. @Autowired resolves by type first, using @Qualifier as a tiebreaker. @Resource resolves by name first, falling back to type. @Inject resolves by type like @Autowired but uses @Named instead of @Qualifier. The critical practical difference is that @Resource works only on fields and setters because its @Target annotation lacks PARAMETER, making it incompatible with constructor injection, which is the modern recommended style.
In Rajesh's banking portfolio service at National Bank of India, two AccountRepository implementations exist: JPA for active account queries and Archive for historical data. The TransferService uses constructor injection with no annotation and Spring auto-detects the single constructor, injecting the @Primary JPA repository. The ReportingService uses @Qualifier to explicitly pick the archive repository. The ComplianceService uses Map injection for runtime selection of either repository. The team never uses @Resource for new code because it cannot do constructor injection, and they rarely use @Inject because @Autowired with required=false gives optional dependency support that @Inject lacks.
The modern answer Pankaj gives in architecture reviews is: single constructor, no annotation, Lombok @RequiredArgsConstructor for zero boilerplate. Use @Autowired only when you genuinely need required=false or have multiple constructors. Everything else is legacy.
Remember one sentence: @Autowired resolves by type, @Resource resolves by name, @Resource cannot do constructor injection, and the modern best practice is no annotation at all with a single constructor.
---