If you’ve spent more than 15 minutes in enterprise Java, you’ve probably seen annotations like:
@Autowired
@Inject
@Resource
@EJB
@ApplicationScoped
@Service
@Component
@Stateless…and immediately wondered:
“Why are there so many ways to inject the same object?”
Welcome to enterprise Java.
The good news?
Once you understand what category these annotations belong to, everything suddenly becomes much simpler.
This article will save you from:
- memorizing random annotations
- confusing CDI with Spring
- pretending to understand EJB during interviews
- opening StackOverflow tabs at 2AM
Let’s make sense of this mess.
There Are ONLY 2 Things Happening
Almost every annotation in this area belongs to one of two buckets:
Dependency Injection: “How do I get this object?”
Scope/Bean Lifecycle: “How long does this object live?”
That’s it. Once you separate these mentally, enterprise Java becomes 10x easier.
Part 1 — Dependency Injection Annotations
These annotations basically say:
“Hey framework, give me this dependency.”
Like ordering coffee from the container.
@Autowired — Spring’s Famous Magic Wand
If Spring had a mascot, it would probably be @Autowired.
@Autowired
private UserService userService;Spring sees this and goes:
“Cool, I’ll find a
UserServicebean for you.”
By default:
- injection happens by type
Meaning:
UserServicenot by variable name.
The Problem: Multiple Beans
Suppose you have:
@Component
class StripePaymentService implements PaymentService {}and:
@Component
class PaypalPaymentService implements PaymentService {}Now Spring panics:
“WHICH ONE DO YOU WANT???”
That’s where @Qualifier comes in:
@Autowired
@Qualifier("stripePaymentService")
private PaymentService service;Now Spring can sleep peacefully again.
Modern Spring Developers Quietly Avoid @Autowired
Plot twist.
Modern Spring code often doesn’t even use it.
Instead:
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
}This is called constructor injection.
And honestly?It’s cleaner, safer, easier to test, and less magical.
Spring automatically injects it. No annotation needed.
@Inject — The “Standard Java” Version
Now imagine someone at Java HQ said:
“Maybe dependency injection should become standardized.”
So CDI/Jakarta EE introduced:
@Inject
private UserService userService;Functionally, this is VERY similar to @Autowired.
Think of it as:
SpringJakarta/CDI@Autowired@Inject
Same idea. Different family.
@Resource — The Old School One
@Resource comes from older Java EE traditions.
@Resource
private DataSource dataSource;Unlike @Autowired, this one usually injects:
- by name first
- then maybe by type
So if your field is:
private DataSource mainDb;the container tries finding a bean literally called:
mainDbThis was super common for:
- databases
- JMS queues
- infrastructure resources
Very enterprise-y…. Very 2009.
@EJB — The Ancient Beast
Ah yes. EJB.
The annotation developers fear during interviews.
@EJB
private PaymentService paymentService;Back in the day, EJBs were THE enterprise solution.
Get Tafsir’s stories in your inbox
Join Medium for free to get updates from this writer.
They handled:
- transactions
- remoting
- pooling
- security
- lifecycle management
Basically:
“What if XML became a framework?”
Modern Spring replaced most EJB use cases with:
@Service
@TransactionalMuch lighter. Much saner. Far fewer therapy sessions.
@PersistenceContext — JPA’s Special Injection
This one injects the JPA EntityManager.
@PersistenceContext
private EntityManager em;Think of it as:
“Give me database superpowers.”
In Spring, people often just do:
@Autowired
private EntityManager em;and Spring handles the rest.
Part 2 — Scope & Lifecycle Annotations
Now we move to the SECOND category. These annotations answer:
“What kind of bean is this?” “How long should it live?”
@Component — The Generic Spring Bean
@Component
public class UserService {
}This tells Spring:
“Manage this class.”
That’s all. By default:
- Spring creates ONE instance
- application-wide singleton
Spring’s Fancy Variants
Spring later added more descriptive versions:
AnnotationMeaning@ComponentGeneric bean@ServiceBusiness logic@RepositoryDatabase layer@ControllerMVC controller@RestControllerREST API controller
Technically similar. But semantically cleaner.
@ApplicationScoped — CDI’s Singleton
CDI equivalent:
@ApplicationScoped
public class UserService {
}Meaning:
“One contextual instance for the entire application lifecycle.”
Conceptually similar behavior as Spring singleton beans.
@RequestScoped — One Bean Per Request
Every HTTP request gets a fresh object.
Useful for:
- request-specific state
- temporary data
- web request processing
CDI:
@RequestScopedSpring:
@RequestScope@SessionScoped — One Bean Per User Session
Useful for:
- shopping carts
- login state
- user preferences
Just don’t abuse it. Otherwise your memory usage becomes:
“surprise production outage.”
@Stateless — The EJB Business Bean
@Stateless
public class PaymentService {
}This means:
- no conversational state
- pooled instances
- transactional service
Think of it as enterprise-grade service objects.
Modern Spring equivalent is roughly:
@Service
@TransactionalNot identical.
But philosophically similar.
The Cheat Sheet Everyone Actually Wants
The Important Thing Most Tutorials Never Explain
These are NOT competing annotations. This is wrong thinking:
@Autowired vs @ApplicationScopedThat’s like comparing:
“car engine” with “parking duration”
Correct comparison:
@Autowired vs @Injectand:
@Component vs @ApplicationScopedTHAT is the real mapping.
Conclusion
Enterprise Java looks terrifying but underneath all the chaos, the concepts are surprisingly simple:
- inject dependencies
- manage object lifecycle
- organize application layers
Once you separate those ideas, the annotation jungle suddenly turns into a small map instead of a horror movie.






