Introduction
Imagine you're building a house. Would you start hammering nails without a blueprint? Probably not. You'd use proven architectural designs to ensure the house is strong, scalable, and easy to maintain.
Software development is no different. We use design patterns proven solutions to recurring problems to make our applications more structured and maintainable. And if you're working with Spring Framework, you're already using some of these patterns, whether you realize it or not!
In this article, we'll explore essential design patterns used in Spring, how they work, and why they matter. We'll break them down with relatable analogies and real-world examples.
1. Singleton Pattern – The One and Only
What is it?
The Singleton Pattern ensures that a class has only one instance and provides a global access point to it.
Where is it used in Spring?
In Spring’s Bean Scope, by default, all beans are Singletons. That means Spring creates only one instance of a bean and reuses it throughout the application.
Real-world analogy:
Think of a president of a country. There is only one at a time, and everyone relies on that one leader. Similarly, Spring keeps a single instance of a bean for efficiency.

Example:
@Component
public class AppConfig {
    public AppConfig() {
        System.out.println("Singleton Bean Initialized");
    }
}

This bean is automatically a singleton. Spring ensures that only one instance of AppConfig is created.

2. Factory Pattern – The Master Builder
What is it?
The Factory Pattern provides a way to create objects without specifying their exact class.
Where is it used in Spring?
Spring’s BeanFactory and ApplicationContext follow the Factory Pattern by creating and managing beans.
Real-world analogy:
Imagine a car factory where you order a car, but you don’t build it yourself. The factory takes care of the complex assembly. Similarly, Spring creates and configures objects for you.
Example:

@Configuration
public class AppConfig {
    @Bean
    public Car getCar() {
        return new Car("Tesla Model X");
    }
}

Here, Spring acts as a factory and provides an instance of Car when needed.

3. Proxy Pattern – The Bodyguard
What is it?
A Proxy Pattern provides an object that acts as a substitute for another object, controlling access to it.
Where is it used in Spring?
Spring uses proxies in AOP (Aspect-Oriented Programming) and Transaction Management.
Real-world analogy:
A celebrity’s bodyguard screens people before they reach the celebrity. Similarly, proxies can restrict, enhance, or log interactions before reaching the actual object.
Example (AOP Proxy):

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void logMethodCall() {
        System.out.println("Method is being called");
    }
}

Here, an AOP proxy intercepts method calls and logs them before execution.

4. Template Method Pattern – The Recipe
What is it?
The Template Method Pattern defines the skeleton of an algorithm and lets subclasses fill in specific details.
Where is it used in Spring?
Spring’s JdbcTemplate, RestTemplate, and TransactionTemplate follow this pattern.
Real-world analogy:
Think of a cooking recipe. The general steps (boil water, add ingredients, cook) remain the same, but the specific ingredients and spices can vary.
Example (JdbcTemplate):

@Autowired
private JdbcTemplate jdbcTemplate;

public void saveUser(User user) {
    String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
    jdbcTemplate.update(sql, user.getName(), user.getEmail());
}

Here, JdbcTemplate handles database interactions so you don’t have to write boilerplate JDBC code.

5. Observer Pattern – The News Reporter
What is it?
The Observer Pattern allows objects (observers) to listen for changes in another object (subject).
Where is it used in Spring?
Spring’s ApplicationEventPublisher follows this pattern to enable event-driven programming.
Real-world analogy:
A news channel broadcasts updates. Subscribers (observers) receive the updates when something new happens.
Example:

@Component
public class UserCreatedEvent extends ApplicationEvent {
    public UserCreatedEvent(Object source) {
        super(source);
    }
}
@Component
public class UserCreatedListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(UserCreatedEvent event) {
        System.out.println("User created event received");
    }
}

Here, UserCreatedListener listens for UserCreatedEvent and takes action when it occurs.

Conclusion
Spring makes heavy use of design patterns to ensure clean, scalable, and efficient code. Whether it's Singletons for efficiency, Factories for object creation, Proxies for security, Template Methods for reducing boilerplate, or Observers for event-driven programming, these patterns help developers build robust applications effortlessly.
By understanding these patterns, you can write better, more maintainable Spring applications and appreciate the elegance of Spring’s design. Next time you write a Spring application, take a moment to recognize these patterns at work!
Happy coding! 🚀