Enterprise intermediate

Singleton EJB vs CDI @ApplicationScoped

Replace Singleton EJBs with CDI @ApplicationScoped beans for simpler shared-state management.

✕ Java EE
@Singleton
@Startup
@ConcurrencyManagement(
    ConcurrencyManagementType.CONTAINER)
public class ConfigCache {
    private Map<String, String> cache;

    @PostConstruct
    public void load() {
        cache = loadFromDatabase();
    }

    @Lock(LockType.READ)
    public String get(String key) {
        return cache.get(key);
    }

    @Lock(LockType.WRITE)
    public void refresh() {
        cache = loadFromDatabase();
    }
}
✓ Jakarta EE 8+
@ApplicationScoped
public class ConfigCache {
    private volatile Map<String, String> cache;

    @PostConstruct
    public void load() {
        cache = loadFromDatabase();
    }

    public String get(String key) {
        return cache.get(key);
    }

    public void refresh() {
        cache = loadFromDatabase();
    }
}
🪶

Less annotation noise

No @ConcurrencyManagement, @Lock, or @Startup — just a single @ApplicationScoped annotation.

🔧

Flexible concurrency

Use java.util.concurrent locks or volatile for exactly the thread-safety you need.

🧪

Easy testing

Plain CDI beans can be instantiated directly in tests without an EJB container.

Old Approach
@Singleton EJB
Modern Approach
@ApplicationScoped CDI
Since JDK
11
Difficulty
intermediate
Singleton EJB vs CDI @ApplicationScoped
Available

Widely available since Jakarta EE 8 / Java 11

Singleton EJBs bundle concurrency management (@Lock, @ConcurrencyManagement) and eager initialisation (@Startup) into the EJB container. A CDI @ApplicationScoped bean achieves the same single-instance lifecycle with far less ceremony. When concurrency control is needed, standard java.util.concurrent utilities give you finer-grained control than the EJB lock annotations.

Share 𝕏 🦋 in