Singleton Pattern in a Spring Boot Project

📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.

▶️ Subscribe to My YouTube Channel (176K+ subscribers): Java Guides on YouTube

▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube

As Java developers, we often hear about design patterns. Some are used frequently, some are misunderstood, and some — like the Singleton Pattern — are baked right into the frameworks we use daily.

In fact, if you’re working with Spring Boot, you’ve probably been using singletons without even realizing it.

This article breaks down:

  • What the Singleton Pattern really is
  • Why it matters in Spring Boot
  • How Spring manages singleton beans under the hood
  • A real-world e-commerce example using singleton services
  • Best practices and when to be careful

Let’s get into it.


What Is the Singleton Pattern?

In simple terms, the Singleton Pattern ensures that:

Only one instance of a class exists across the entire application.

This is useful when:

  • You want to avoid duplicate objects
  • You need a centralized point of control (e.g., configuration, caching, logging)
  • You’re managing shared state or resources

Plain Java Singleton Example:

public class AppConfig {
    private static AppConfig instance;

    private AppConfig() {}

    public static AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }
}

This is a classic singleton. But in Spring Boot, you don’t usually write it like this. Spring does the job for you.


How Spring Boot Uses Singleton by Default

In Spring, beans are singleton by default.

That means:

  • You define a class with @Component or @Service
  • Spring creates only one instance of that class
  • It’s managed in the application context and shared across all dependent components

Example:

@Service
public class EmailService {
    public void send(String to, String subject, String body) {
        // logic to send email
    }
}

Now if OrderService, UserService, and AdminService all inject EmailService, they get the same instance.

@Autowired
private EmailService emailService;

🎯 That’s a Singleton Pattern in action — no extra code required.


Real-World Example: E-Commerce Order Processing

Let’s say we’re building an e-commerce app where we process customer orders. We want to:

  • Validate the cart
  • Check inventory
  • Process payment
  • Send confirmation email

We’ll use Spring Boot and apply the Singleton Pattern naturally through Spring-managed beans.


✅ Step 1: Create a Singleton Email Service

@Service
public class EmailService {

    public void sendOrderConfirmation(String customerEmail, String orderId) {
        System.out.println("Sending confirmation email to " + customerEmail + " for Order #" + orderId);
        // In real life: use JavaMailSender, templates, etc.
    }
}

This bean is a singleton by default.


✅ Step 2: Create Inventory Service

@Service
public class InventoryService {

    public boolean isInStock(String productId, int quantity) {
        // Simulate DB call
        return true; // Assume always in stock for now
    }
}

Again, this is a singleton bean.


✅ Step 3: Order Service (uses Singleton Services)

@Service
public class OrderService {

    private final EmailService emailService;
    private final InventoryService inventoryService;

    @Autowired
    public OrderService(EmailService emailService, InventoryService inventoryService) {
        this.emailService = emailService;
        this.inventoryService = inventoryService;
    }

    public void placeOrder(String customerEmail, String productId, int quantity) {
        if (!inventoryService.isInStock(productId, quantity)) {
            throw new RuntimeException("Product is out of stock!");
        }

        String orderId = UUID.randomUUID().toString(); // Simulated order ID

        System.out.println("Order placed: " + orderId);

        emailService.sendOrderConfirmation(customerEmail, orderId);
    }
}

Here, OrderService depends on two singleton services: EmailService and InventoryService.


✅ Step 4: Controller to Test It

@RestController
@RequestMapping("/api/orders")
public class OrderController {

    private final OrderService orderService;

    @Autowired
    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public ResponseEntity<String> placeOrder(@RequestParam String email,
                                             @RequestParam String productId,
                                             @RequestParam int quantity) {
        orderService.placeOrder(email, productId, quantity);
        return ResponseEntity.ok("Order placed successfully!");
    }
}

Run your Spring Boot app and hit the endpoint:

POST http://localhost:8080/api/orders?email=test@example.com&productId=123&quantity=1

✅ It works. And guess what?

  • All services were singletons
  • No manual singleton code required
  • Managed cleanly by Spring

How Can You Confirm It's a Singleton?

Let’s test it.

Modify EmailService and add:

@PostConstruct
public void init() {
    System.out.println("EmailService initialized: " + this);
}

You’ll see the message only once in the logs — no matter how many times you inject or use it.

That proves Spring created only one instance.

🎯 Spring’s IoC container ensures singleton scope by default unless you specify otherwise.


Scope Options in Spring

If you ever want a different scope, Spring gives you options:

Scope Description
singleton One instance per Spring context (default)
prototype New instance every time it's requested
request One instance per HTTP request (web apps)
session One per HTTP session (web apps)

For most stateless services, singleton is perfect.


When Singleton May NOT Be Ideal

Singletons are powerful — but be cautious:

1. Stateful Services

Don’t store per-user or per-request state inside a singleton bean. It’s shared across users.

❌ Bad:

@Service
public class CartService {
    private List<String> items = new ArrayList<>(); // shared!
}

✅ Better:

Pass data as parameters, or store it in request/session scope if needed.

2. Thread Safety

Singleton beans are shared — meaning multiple threads may use them. If your bean modifies shared variables, use proper synchronization or avoid mutability.

3. Testing and Isolation

Singletons can create hidden dependencies between tests if not cleaned up. Prefer using mock beans and Spring’s test context management.


Summary

Topic Key Takeaway
Singleton pattern Ensures only one instance of a class exists
Spring beans Singleton by default
Use case Stateless services like email, payment, logging
Real-world usage Inject same instance into multiple components
Caution Avoid storing state or mutable data in singletons

Final Thoughts

The Singleton Pattern is one of the most used — and most misunderstood — design patterns. But when you're working in a Spring Boot project, it's built right in.

You don’t have to write getInstance() or manage private constructors. Just annotate your service class, and let Spring handle the rest.

Use singletons for shared, stateless logic. Keep them clean, testable, and thread-safe — and you’ll be using one of the oldest patterns in modern, production-grade applications.

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare