Master Spring Design Patterns: Simple Factory to Observer Explained
This article explores key Spring framework design patterns—including simple factory, factory method, singleton, adapter, decorator, proxy, observer, and template method—detailing their implementation, underlying principles, and code examples, while also highlighting a comprehensive Java tutorial resource.
1. Simple Factory (not one of the 23 design patterns)
Implementation
BeanFactoryin Spring is an embodiment of the simple factory pattern; it returns a bean object based on a unique identifier, with creation timing depending on the situation.
The essence is that a factory class decides dynamically which product class to create based on the supplied parameters.
Principle
Bean container startup phase
The XML configuration is read and each bean element is converted into a BeanDefinition object.
These definitions are registered in the BeanDefinitionRegistry and stored in the factory's internal map.
After registration, Spring provides an extension point via the BeanFactoryPostProcessor interface, allowing custom code insertion.
Typical example: PropertyPlaceholderConfigurer injects placeholder values into a data source configuration.
Bean instantiation phase
Instantiation uses reflection or CGLIB, and Spring exposes several extension points:
Various Aware interfaces , e.g., BeanFactoryAware, which inject the corresponding BeanFactory instance into beans that implement them.
BeanPostProcessor interface , where Spring calls the methods of beans implementing BeanPostProcessor during instantiation.
InitializingBean interface , whose afterPropertiesSet method is invoked.
DisposableBean interface , whose destroy method is called when the bean is destroyed.
Design significance
Loose coupling: dependencies are injected by the beanFactory instead of hard‑coded, introducing a third party (Spring) to resolve bean relationships.
Additional bean processing: by implementing Spring’s extension interfaces, custom logic can be executed during the bean lifecycle.
2. Factory Method
Implementation
Implemented via the FactoryBean interface. When a bean implements FactoryBean, Spring calls its getObject() method during getBean() retrieval, returning the object produced by the factory rather than the factory itself.
Typical example: the integration of Spring with MyBatis uses a FactoryBean to expose a SqlSessionFactory instance.
Code illustration:
3. Singleton Pattern
Spring’s default bean scope is singleton; all beans are created and cached by the AbstractBeanFactory during getBean execution.
Key method implementation:
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);
}ps: Spring’s dependency injection uses a double‑checked locking singleton implementation.
Summary: the singleton pattern guarantees a single instance and provides a global access point; Spring implements this via the BeanFactory without enforcing constructor‑level singleton control.
4. Adapter Pattern
In Spring MVC, the HandlerAdapter adapts different handler types to a common execution flow.
During request processing, DispatcherServlet obtains a handler from HandlerMapping, then delegates to the appropriate HandlerAdapter, which finally returns a ModelAndView to the servlet.
Design significance: adding a new controller type only requires implementing a corresponding HandlerAdapter, making the framework easily extensible.
5. Decorator Pattern
Spring uses wrapper classes whose names contain Wrapper or Decorator to add responsibilities to existing objects dynamically.
The decorator approach is more flexible than creating subclasses because behavior can be layered at runtime.
6. Proxy Pattern
Spring AOP is built on dynamic proxy mechanisms; it creates proxy objects at runtime without requiring manual proxy class code.
Static proxies are also possible, where developers write a proxy class that delegates to the target.
When weaving aspects, the AOP container creates a proxy for the target bean, and the proxy intercepts method calls to apply advice.
7. Observer Pattern
Spring’s event‑driven model follows the observer pattern. Core components are the event source, the event object, and the listener.
Key classes and interfaces:
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() { return this.timestamp; }
} ApplicationListener<E extends ApplicationEvent>extends EventListener and defines a single method onApplicationEvent(E event).
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
} ApplicationEventPublisherprovides publishEvent(ApplicationEvent event) to broadcast events to all registered listeners.
public interface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
}The abstract AbstractApplicationContext registers listeners during context refresh and delegates event multicasting to an ApplicationEventMulticaster.
8. Strategy Pattern (Resource Access)
Spring’s Resource interface abstracts various resource‑access strategies (URL, classpath, filesystem, servlet context, input stream, byte array). It defines methods such as getInputStream(), exists(), isOpen(), getDescription(), getFile(), and getURL().
Concrete implementations include UrlResource, ClassPathResource, FileSystemResource, ServletContextResource, InputStreamResource, and ByteArrayResource, each providing the appropriate access logic.
9. Template Method Pattern
Spring combines the template method pattern with callback interfaces to simplify resource handling. For example, JdbcTemplate defines a final execute method that manages connection and statement lifecycle, while delegating the actual work to a StatementCallback.
public abstract class JdbcTemplate {
public final Object execute(String sql) {
Connection con = null;
Statement stmt = null;
try {
con = getConnection();
stmt = con.createStatement();
Object retValue = executeWithStatement(stmt, sql);
return retValue;
} finally {
closeStatement(stmt);
releaseConnection(con);
}
}
protected abstract Object executeWithStatement(Statement stmt, String sql);
}The callback interface:
<code>public interface StatementCallback {
Object doWithStatement(Statement stmt);
}Usage example:
JdbcTemplate jdbcTemplate = ...;
final String sql = "SELECT * FROM users";
StatementCallback callback = new StatementCallback() {
public Object doWithStatement(Statement stmt) {
// execute query and process ResultSet
return null;
}
};
jdbcTemplate.execute(callback);By separating the invariant workflow (resource acquisition and release) from the variable business logic (the callback), Spring achieves reusable, maintainable code without requiring inheritance for each use case.
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.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
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.
