Backend Development 15 min read

Spring Framework Design Patterns: Summary and Implementation Details

This article provides a comprehensive overview of the design patterns used in the Spring framework—including Simple Factory, Factory Method, Singleton, Adapter, Decorator, Proxy, Observer, Strategy, and Template Method—explaining their implementation, underlying principles, and practical significance with code examples.

Java Captain
Java Captain
Java Captain
Spring Framework Design Patterns: Summary and Implementation Details

1. Simple Factory (not one of the 23 GoF patterns)

In Spring, BeanFactory is an example of the simple factory pattern: a unique identifier is passed to obtain a bean instance, with creation timing (eager or lazy) determined by the specific configuration.

The essence is a factory class that decides, based on input parameters, which product class to instantiate.

Implementation Principle

During bean container startup, Spring reads bean XML definitions, converts each <bean> element into a BeanDefinition , and registers them in the BeanFactory 's internal map.

After registration, developers can hook custom logic via BeanFactoryPostProcessor . A typical example is PropertyPlaceholderConfigurer , which injects placeholder values into data source configurations.

During bean instantiation, Spring offers several extension points:

Various Aware interfaces (e.g., BeanFactoryAware ) – Spring injects the corresponding BeanFactory instance into beans that implement them.

BeanPostProcessor – Spring calls its methods before and after bean initialization.

InitializingBean – beans can execute custom logic after properties are set.

DisposableBean – beans can release resources when the container destroys them.

Design Significance

It achieves loose coupling by delegating dependency resolution to the BeanFactory instead of hard‑coded references, and it allows additional processing of beans through the aforementioned interfaces.

2. Factory Method

Implemented via the FactoryBean interface. When a bean implements FactoryBean , Spring calls its getObject() method during getBean() , returning the object produced by the factory rather than the factory itself.

Typical usage: integration of Spring with MyBatis, where SqlSessionFactoryBean implements FactoryBean and returns a SqlSessionFactory instance.

3. Singleton Pattern

Spring beans are singleton by default. The container creates a single instance and provides a global access point through BeanFactory . The actual singleton implementation resides in AbstractBeanFactory.getSingleton() , which uses double‑checked locking and early‑reference handling to resolve circular dependencies.

public Object getSingleton(String beanName) {
    // allow early reference
    return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory
singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

Spring’s singleton differs from the classic pattern: it does not enforce a private constructor; instead, the container manages the lifecycle of any Java object.

4. Adapter Pattern

Spring MVC uses HandlerAdapter to adapt various handler types. The DispatcherServlet obtains a handler from HandlerMapping , then delegates execution to the appropriate HandlerAdapter , which returns a ModelAndView to the servlet.

This design makes it easy to extend the controller layer: adding a new handler only requires a corresponding adapter.

5. Decorator Pattern

Spring’s wrapper classes (named with Wrapper or Decorator ) dynamically add responsibilities to objects without subclassing, providing more flexible functionality enhancement.

6. Proxy Pattern

AOP in Spring is built on dynamic proxying. Spring can create proxies at runtime (dynamic proxy) or use manually written proxy classes (static proxy). The proxy intercepts method calls, applies advice, and forwards the call to the target bean.

7. Observer Pattern

Spring’s event‑driven model follows the observer pattern. An ApplicationEvent (subject) is published by the ApplicationEventPublisher . Listeners implement ApplicationListener and receive events via the onApplicationEvent() method.

public abstract class ApplicationEvent extends EventObject {
    private final long timestamp = System.currentTimeMillis();
    public ApplicationEvent(Object source) { super(source); }
    public final long getTimestamp() { return this.timestamp; }
}
public interface ApplicationListener
extends EventListener {
    void onApplicationEvent(E event);
}

8. Strategy Pattern

Spring’s Resource abstraction is a classic strategy: the interface defines operations (e.g., getInputStream() , exists() ), while concrete implementations such as UrlResource , ClassPathResource , FileSystemResource , etc., provide the actual access logic for different underlying resources.

9. Template Method Pattern

Spring frequently combines the template method with callbacks. For example, JdbcTemplate defines a final execute() method that manages connection and statement lifecycle, while delegating the actual SQL execution to a StatementCallback supplied by the caller.

public final Object execute(String sql) {
    Connection con = null;
    Statement stmt = null;
    try {
        con = getConnection();
        stmt = con.createStatement();
        Object ret = executeWithStatement(stmt, sql);
        return ret;
    } finally {
        closeStatement(stmt);
        releaseConnection(con);
    }
}

protected abstract Object executeWithStatement(Statement stmt, String sql);

To avoid subclassing, Spring introduces a callback interface:

public interface StatementCallback {
    Object doWithStatement(Statement stmt);
}

The caller passes an implementation of StatementCallback to JdbcTemplate.execute(callback) , allowing custom logic while reusing the template’s resource management.

Overall, Spring’s extensive use of these patterns enables extensibility, loose coupling, and clean separation of concerns throughout the framework.

design patternsProxySpringtemplate methodsingletonadapterstrategydecoratorObserverFactory MethodBeanFactory
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.