Unlock Spring’s Power: 9 Essential Design Patterns Every Backend Engineer Should Master
This article explores nine key Spring framework design patterns—including Simple Factory, Factory Method, Singleton, Adapter, Decorator, Proxy, Observer, Strategy, and Template Method—detailing their implementation, underlying principles, and practical code examples, while highlighting how they enable loose coupling and extensibility in backend development.
Spring heavily relies on classic design patterns to provide a flexible, extensible, and loosely‑coupled IoC container. The following nine patterns illustrate how Spring implements dependency injection, bean lifecycle management, and extensibility.
1. Simple Factory (BeanFactory)
Implementation: BeanFactory retrieves a bean by a unique identifier.
Essence: a factory class decides which product class to instantiate based on supplied parameters.
Bean creation process:
Read bean XML definitions and convert each <bean> element into a BeanDefinition object.
Register the BeanDefinition in the BeanFactory 's internal ConcurrentHashMap.
Allow custom processing via BeanFactoryPostProcessor (e.g., PropertyPlaceholderConfigurer).
Instantiation phase:
Inject dependencies through Aware interfaces (e.g., BeanFactoryAware).
Apply BeanPostProcessor callbacks before and after initialization.
Support InitializingBean and DisposableBean lifecycle hooks.
2. Factory Method (FactoryBean)
Implementation: beans that implement FactoryBean act as factories.
Principle: getObject() is invoked when getBean() is called, returning the product rather than the factory itself.
Typical example: Spring‑MyBatis integration where SqlSessionFactoryBean returns a SqlSessionFactory instance.
3. Singleton Pattern
Spring beans are singleton by default; creation occurs in AbstractBeanFactory.getBean() via getSingleton().
public Object getSingleton(String beanName) {
// allow early references
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);
}The above method demonstrates Spring's double‑checked locking approach to ensure a true singleton.
4. Adapter Pattern (HandlerAdapter)
Implementation: Spring MVC’s HandlerAdapter selects and invokes the appropriate handler based on mapping rules.
Process: DispatcherServlet obtains a handler from HandlerMapping, forwards the request to the matching HandlerAdapter, which then returns a ModelAndView to the servlet.
Benefit: Adding a new controller type only requires a corresponding adapter.
5. Decorator Pattern
Implementation: Classes whose names contain Wrapper or Decorator act as decorators, dynamically adding responsibilities to a bean.
Advantage: More flexible than subclassing for extending functionality.
6. Proxy Pattern (AOP)
Implementation: Spring AOP builds dynamic proxies (or static proxies) to weave aspects at runtime.
Key interfaces: BeanPostProcessor, ApplicationListener, etc., are proxied to inject cross‑cutting behavior.
Note: "Weaving" means applying an aspect to a target object and creating a new proxy instance.
7. Observer Pattern (Application Events)
Implementation: Spring’s event‑driven model follows the observer pattern.
Event source: ApplicationContext (implements ApplicationEventPublisher).
Event: subclasses of ApplicationEvent (extends EventObject).
Listener: classes implementing ApplicationListener<E extends ApplicationEvent>.
public abstract class ApplicationEvent extends EventObject {
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() { return this.timestamp; }
} public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}8. Strategy Pattern (Resource Interface)
Implementation: Spring’s Resource abstraction defines a strategy for accessing various underlying resources (URL, classpath, filesystem, servlet context, etc.).
Key methods: getInputStream(), exists(), isOpen(), getDescription(), getFile(), getURL().
Concrete implementations include UrlResource, ClassPathResource, FileSystemResource, ServletContextResource, InputStreamResource, and ByteArrayResource.
9. Template Method Pattern
Definition: A superclass defines the algorithm skeleton; subclasses provide specific steps.
Common methods are reused; abstract methods must be overridden; hook methods can be optionally overridden.
Spring usage: Most framework extensions (e.g., JdbcTemplate, Hibernate integration) combine template method with callback interfaces.
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;
} finally {
closeStatement(stmt);
releaseConnection(con);
}
}
protected abstract Object executeWithStatement(Statement stmt, String sql);
} public interface StatementCallback {
Object doWithStatement(Statement stmt);
} public final Object execute(StatementCallback callback) {
Connection con = null;
Statement stmt = null;
try {
con = getConnection();
stmt = con.createStatement();
Object ret = callback.doWithStatement(stmt);
return ret;
} finally {
closeStatement(stmt);
releaseConnection(con);
}
}By separating the invariant resource‑management code from the variable business logic, Spring achieves high reusability and clean separation of concerns.
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.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
