What is a Bean?

Understanding Managed Components in Jakarta EE

← Back to Index

What is a Bean?

Think of a bean like a plant in a greenhouse:

A Bean is simply a Java object that is managed by a container (CDI container, EJB container, etc.). The container creates it, injects dependencies, manages its lifecycle, and destroys it.

Key Point: You don't create beans with 'new' - the container does it for you!

Regular Object vs Bean

// Regular Object - You manage everything
public class RegularClass {
    private Database db = new Database();  // Manual creation

    public RegularClass() {
        // You handle initialization
    }

    public void cleanup() {
        db.close();  // You handle cleanup
    }
}

RegularClass obj = new RegularClass();  // You create it
obj.cleanup();  // You clean it up

// CDI Bean - Container manages everything
@ApplicationScoped  // This makes it a bean!
public class ManagedBean {
    @Inject  // Container injects dependencies
    private Database db;

    @PostConstruct  // Container calls after creation
    public void init() {
        // Automatic initialization
    }

    @PreDestroy  // Container calls before destruction
    public void cleanup() {
        // Automatic cleanup
    }
}

// You just inject it - container creates/manages it
@Inject
private ManagedBean bean;  // Container provides it

Types of Beans in Jakarta EE

1. CDI Beans (Managed Beans)

Most common type - any POJO with a scope annotation

@RequestScoped  // Scope makes it a CDI bean
public class UserService {
    @Inject
    private UserRepository repository;

    public User findUser(Long id) {
        return repository.find(id);
    }
}

Characteristics:

2. Enterprise JavaBeans (EJB)

Server-side components with extra features

@Stateless  // EJB annotation
public class PaymentService {
    @Inject
    private PaymentGateway gateway;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void processPayment(Order order) {
        gateway.charge(order.getTotal());
    }
}

Characteristics:

3. JPA Entities

Represent database tables

@Entity  // JPA annotation
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue
    private Long id;

    private String username;
    private String email;

    // Getters/setters
}

Characteristics:

4. JSF Managed Beans

Backing beans for JSF views (older style)

@Named  // Makes it accessible from JSF views
@ViewScoped
public class UserController {
    private String username;
    private String password;

    @Inject
    private AuthService authService;

    public String login() {
        if (authService.authenticate(username, password)) {
            return "dashboard?faces-redirect=true";
        }
        return null;
    }

    // Getters/setters for view binding
}
Bean Type Annotation Container Use Case
CDI Bean @RequestScoped, @ApplicationScoped CDI General business logic
EJB @Stateless, @Stateful EJB + CDI Transactions, security, timers
JPA Entity @Entity JPA Database mapping
JSF Bean @Named + scope CDI JSF view backing beans

Bean Lifecycle

CDI Bean Lifecycle

1. Container scans for beans (at startup)
   ↓
2. User requests bean (via @Inject or direct access)
   ↓
3. Container creates instance (calls constructor)
   ↓
4. Container injects dependencies (@Inject fields/setters)
   ↓
5. Container calls @PostConstruct method
   ↓
6. Bean is ready to use
   ↓
   ... bean is used by application ...
   ↓
7. Scope ends (request ends, session expires, app shuts down)
   ↓
8. Container calls @PreDestroy method
   ↓
9. Bean is destroyed and garbage collected

Complete Lifecycle Example

@RequestScoped
public class LifecycleDemo {

    // 1. Constructor called
    public LifecycleDemo() {
        System.out.println("1. Constructor called");
    }

    // 2. Dependency injected after construction
    @Inject
    private Database database;

    // 3. Called after injection is complete
    @PostConstruct
    public void init() {
        System.out.println("2. @PostConstruct - database is now available");
        // Safe to use injected dependencies here
        database.connect();
    }

    // 4. Business methods can now be called
    public void doWork() {
        System.out.println("3. Doing work with database");
        database.query("SELECT * FROM users");
    }

    // 5. Called before bean is destroyed
    @PreDestroy
    public void cleanup() {
        System.out.println("4. @PreDestroy - cleaning up");
        database.disconnect();
    }
}

Output during a request:

1. Constructor called
2. @PostConstruct - database is now available
3. Doing work with database
4. @PreDestroy - cleaning up

How to Make a Class a Bean

Option 1: Add a Scope Annotation (Most Common)

@RequestScoped  // Now it's a CDI bean!
public class MyService {
    // Bean code
}

Option 2: Add @Named (For JSF Access)

@Named  // Accessible from JSF with #{myController}
@RequestScoped
public class MyController {
    // Bean code
}

Option 3: Just Use It (Implicit Bean)

// No annotations needed if it has @Inject
public class SimpleService {
    @Inject
    private Database db;  // Makes it a @Dependent bean

    public void doSomething() { }
}

What Makes a Class NOT a Bean?

// ❌ Regular POJO - not a bean
public class RegularClass {
    // No scope, no @Inject, no EJB annotation
    public void doSomething() { }
}

// Created manually
RegularClass obj = new RegularClass();  // Not managed

// ❌ Entity alone - not a CDI bean
@Entity
public class User {
    // JPA entity, but not a CDI bean unless you add a scope
}

Bean Discovery Modes

Configuration in beans.xml:

1. bean-discovery-mode="all" (Default in older versions)

<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
       version="4.0"
       bean-discovery-mode="all">
    <!-- All classes become beans -->
</beans>

All classes in the archive are CDI beans (even without annotations)

2. bean-discovery-mode="annotated" (Recommended)

<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
       version="4.0"
       bean-discovery-mode="annotated">
    <!-- Only annotated classes become beans -->
</beans>

Only classes with bean-defining annotations become beans (more performant)

3. bean-discovery-mode="none"

<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
       version="4.0"
       bean-discovery-mode="none">
    <!-- No automatic bean discovery -->
</beans>

CDI disabled for this archive (unless explicitly configured)

Proxies - How CDI Works Behind the Scenes

CDI doesn't inject actual objects - it injects proxies!

@RequestScoped
public class UserService {
    public User getUser() {
        return new User("Alice");
    }
}

@ApplicationScoped
public class MyBean {
    @Inject
    private UserService userService;  // This is a PROXY, not the real object!
}

Why proxies?

Proxy Requirements

Best Practices

✅ DO:

  • Use CDI beans for business logic - Default choice
  • Use EJBs only when needed - For transactions, security, timers
  • Keep entities simple - No business logic in JPA entities
  • Choose the right scope - @RequestScoped for most cases
  • Use @PostConstruct for initialization - Dependencies are ready
  • Make beans serializable if needed - Required for @SessionScoped
  • Use bean-discovery-mode="annotated" - Better performance

❌ DON'T:

  • Don't create beans with 'new' - Let the container manage them
  • Don't make beans final - CDI needs to create proxies
  • Don't put business logic in entities - Separate concerns
  • Don't initialize in constructor - Injected fields aren't ready yet
  • Don't store heavy objects in @SessionScoped - Memory issues
  • Don't inject narrow scopes into wide scopes - Use Provider instead

Summary

  • Bean = Java object managed by a container
  • CDI Beans: General-purpose, @Inject support, lifecycle management
  • EJBs: CDI beans + transactions, security, async, timers
  • JPA Entities: Database mapping (not CDI beans unless scoped)
  • JSF Beans: View backing beans with @Named
  • Lifecycle: Constructor → Injection → @PostConstruct → Use → @PreDestroy → Destroy
  • Scopes control: How long beans live and how many instances exist
  • Proxies: CDI uses proxies to enable context awareness
  • No 'new' keyword: Container creates and manages beans
  • Benefits: Automatic lifecycle, dependency injection, loose coupling