How Spring Implements 9 Classic Design Patterns – From Simple Factory to Template Method
This article explains how the Spring framework embodies nine classic design patterns—including Simple Factory, Factory Method, Singleton, Adapter, Decorator, Proxy, Strategy, Observer, and Template Method—detailing their implementation principles, core code snippets, and the benefits they bring to dependency injection and bean lifecycle management.
Simple Factory (BeanFactory) in Spring
Spring's BeanFactory is an example of the simple factory pattern: it creates bean instances based on a unique identifier, with the creation timing (eager or lazy) determined by the specific configuration.
Essence
A factory class decides which product class to instantiate based on the provided parameters.
Implementation Principle
Bean container startup phase:
Read bean XML configuration files and convert each <bean> element into a BeanDefinition object.
Register these BeanDefinition objects in the BeanFactory via BeanDefinitionRegistry, storing them in a ConcurrentHashMap.
After registration, Spring provides an extension point through BeanFactoryPostProcessor allowing custom code insertion, e.g., PropertyPlaceholderConfigurer for placeholder resolution.
Bean instantiation phase:
Beans are instantiated via reflection or CGLIB. Spring exposes several extension points during this phase:
Aware interfaces (e.g., BeanFactoryAware) – Spring injects the corresponding factory instance into beans that implement these interfaces.
BeanPostProcessor – Methods are invoked before and after bean initialization.
InitializingBean – Provides an afterPropertiesSet() callback.
DisposableBean – Provides a destroy() callback when the bean is disposed.
Design Significance
Loose coupling: Dependencies are injected by the BeanFactory instead of being hard‑coded, introducing a third party (Spring) that resolves bean relationships.
Additional bean processing: By implementing specific interfaces, developers can hook into the bean lifecycle for custom behavior.
Factory Method
Implementation
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.
Example
Typical usage: integration of Spring with MyBatis, where SqlSessionFactoryBean implements FactoryBean and returns a SqlSessionFactory instance.
Singleton Pattern
Spring's default bean scope is singleton. Bean creation occurs in AbstractBeanFactory.getBean(), which ultimately calls getSingleton(). The method uses double‑checked locking to ensure a single instance.
public Object getSingleton(String beanName) {
// allow early references
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Check cache for existing instance
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);
}Summary: The singleton pattern guarantees a single instance and provides a global access point; Spring implements this at the container level, managing bean lifecycles without enforcing constructor‑level singleton constraints.
Adapter Pattern
Implementation
Spring MVC uses HandlerAdapter to adapt various handler types. The DispatcherServlet obtains a handler from HandlerMapping, then delegates to the appropriate HandlerAdapter, which executes the handler and returns a ModelAndView.
Significance
Adding a new controller type only requires a new HandlerAdapter, making controller extension straightforward.
Decorator Pattern
Implementation
Spring employs wrapper/decorator classes (e.g., classes with Wrapper or Decorator in their names) to dynamically add responsibilities to objects, offering more flexibility than subclassing.
Proxy Pattern
Implementation
AOP in Spring is built on dynamic proxy mechanisms. Dynamic proxies are created in memory without manual proxy class code, while static proxies require explicit implementation.
Mechanism
During runtime, aspects are woven into target objects, and the AOP container creates a proxy that delegates method calls to the target while applying advice.
Observer Pattern
Implementation
Spring's event‑driven model follows the observer pattern. Core components include:
ApplicationEvent – Abstract base class for all events (extends EventObject).
ApplicationListener<E extends ApplicationEvent> – Interface for event listeners.
ApplicationEventPublisher – Interface for publishing events.
AbstractApplicationContext – Registers listeners and delegates event multicasting.
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<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}Strategy Pattern
Implementation
Spring's Resource interface abstracts resource access strategies. Various implementations (e.g., UrlResource, ClassPathResource, FileSystemResource, etc.) provide concrete access to different underlying resources.
Template Method Pattern
Essence
The template method defines a skeleton algorithm in a superclass, leaving specific steps to subclasses or callbacks. Spring uses this pattern extensively, often combined with callback interfaces.
Example – JdbcTemplate
public abstract class JdbcTemplate {
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;
} catch (SQLException e) {
// handle exception
} finally {
closeStatement(stmt);
releaseConnection(con);
}
}
protected abstract Object executeWithStatement(Statement stmt, String sql);
}To avoid subclassing for each operation, Spring introduces a callback interface:
public interface StatementCallback {
Object doWithStatement(Statement stmt);
} public class JdbcTemplate {
public final Object execute(StatementCallback callback) {
Connection con = null;
Statement stmt = null;
try {
con = getConnection();
stmt = con.createStatement();
return callback.doWithStatement(stmt);
} catch (SQLException e) {
// handle exception
} finally {
closeStatement(stmt);
releaseConnection(con);
}
}
}Usage:
JdbcTemplate jdbcTemplate = ...;
final String sql = "SELECT * FROM users";
StatementCallback callback = new StatementCallback() {
public Object doWithStatement(Statement stmt) {
// execute query and process ResultSet
return ...;
}
};
jdbcTemplate.execute(callback);By passing a callback, the varying logic is isolated while the template handles resource acquisition and cleanup.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
