How Spring Implements 9 Core Design Patterns – From Simple Factory to Template Method

This article explains how Spring applies nine classic design patterns—including Simple Factory, Factory Method, Singleton, Adapter, Decorator, Proxy, Observer, Strategy, and Template Method—detailing their implementation approaches, underlying principles, and the benefits they bring to Spring's IoC container and AOP mechanisms.

ITFLY8 Architecture Home
ITFLY8 Architecture Home
ITFLY8 Architecture Home
How Spring Implements 9 Core Design Patterns – From Simple Factory to Template Method

Spring's design pattern summary covers nine patterns: Simple Factory, Factory Method, Singleton, Adapter, Decorator, Proxy, Observer, Strategy, and Template Method.

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

Implementation

BeanFactory in Spring is an embodiment of the simple factory pattern: it returns a bean instance based on a unique identifier, with creation timing determined by the specific scenario.

Essence

A factory class decides which product class to instantiate based on the provided parameters.

Principle

Bean container startup phase:

Read bean XML configuration files and convert each bean element into a BeanDefinition object.

Register these BeanDefinition objects into the BeanFactory via BeanDefinitionRegistry, storing them in a ConcurrentHashMap.

After registration, Spring offers 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, during which Spring exposes many extension points:

Aware interfaces (e.g., BeanFactoryAware) – Spring injects the corresponding BeanFactory instance into beans implementing these interfaces.

BeanPostProcessor – Spring invokes its methods during bean instantiation.

InitializingBean – Spring calls its methods after property injection.

DisposableBean – Spring calls its methods when the bean is destroyed.

Design significance

Loose coupling : By delegating dependency resolution to the BeanFactory, hard‑coded dependencies become configurable, achieving loose coupling.

Additional bean processing : Implementing Spring’s extension interfaces allows extra handling during the bean lifecycle; the [Very Important] note emphasizes this.

2. Factory Method

Implementation

Use the FactoryBean interface.

Principle

A bean that implements FactoryBean is a factory bean; when getBean() is called, Spring automatically invokes its getObject() method and returns the result instead of the factory itself.

Example

Typical example: integration of Spring with MyBatis.

Code example:

Spring FactoryBean example
Spring FactoryBean example

Explanation:

The bean shown implements FactoryBean, so the returned object is the result of SqlSessionFactoryBean.getObject(), not the SqlSessionFactoryBean instance itself.

3. Singleton Pattern

Spring’s default bean scope is singleton.

Dependency injection (including lazy‑init) occurs in AbstractBeanFactory.getBean. The doGetBean method calls getSingleton to create the bean.

Analysis of getSingleton() method:

public Object getSingleton(String beanName){
    // parameter true allows 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)) {
        // lock and handle early reference
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // invoke getObject of the factory
                    singletonObject = singletonFactory.getObject();
                    // record in cache; earlySingletonObjects and singletonFactories are mutually exclusive
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

Process diagram: Spring uses double‑checked locking for singleton bean creation.

Spring singleton process diagram
Spring singleton process diagram

Summary

Singleton definition: Ensure a class has only one instance and provide a global access point.

Spring’s implementation: Spring provides the global access point via BeanFactory, but does not enforce singleton at the constructor level because it manages arbitrary Java objects.

4. Adapter Pattern

Implementation

Spring MVC’s HandlerAdapter.

Principle

HandlerAdapter

selects and executes the appropriate handler based on handler rules.

Process

DispatcherServlet

obtains a handler from HandlerMapping, then forwards the request to the corresponding HandlerAdapter, which invokes the handler and returns a ModelAndView to the servlet.

Significance

Adding a new controller only requires a new handler and its matching adapter, making extension straightforward.

5. Decorator Pattern

Implementation

Spring uses wrapper classes whose names contain Wrapper or Decorator.

Essence

Dynamically adds additional responsibilities to an object.

Compared with subclassing, the decorator offers more flexibility for adding functionality.

6. Proxy Pattern

Implementation

AOP in Spring is built on the dynamic proxy pattern.

Dynamic proxy

Created in memory without manually writing proxy classes.

Static proxy

Requires a hand‑written proxy class that delegates to the target object.

Principle

Aspects are woven at runtime; Spring AOP creates a proxy for the target object and injects the aspect logic.

Weaving

Weaving means applying an aspect to a target object and creating a new proxy.

7. Observer Pattern

Implementation

Spring’s event‑driven model uses the observer pattern; listeners implement the observer role.

Specifics

Three parts are required: event source, event, and event listener.

ApplicationEvent (abstract class) extends java.util.EventObject and carries a timestamp.

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 interface extends EventListener with a single method onApplicationEvent(E event).

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E event);
}

ApplicationContext is the global container (the event source) and implements ApplicationEventPublisher.

public interface ApplicationEventPublisher {
    void publishEvent(ApplicationEvent event);
}

Spring’s AbstractApplicationContext registers listeners and publishes events via an ApplicationEventMulticaster.

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {
    private ApplicationEventMulticaster applicationEventMulticaster;
    protected void registerListeners() {
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String lisName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(lisName);
        }
    }
}

8. Strategy Pattern

Implementation

Spring’s Resource interface provides a flexible strategy for accessing various underlying resources.

Resource interface overview

The interface defines methods such as getInputStream(), exists(), isOpen(), getDescription(), getFile(), and getURL(). Different implementations handle different resource types.

Implementations include:

UrlResource – accesses network resources.

ClassPathResource – accesses class‑path resources.

FileSystemResource – accesses file‑system resources.

ServletContextResource – accesses resources relative to the servlet context.

InputStreamResource – wraps an InputStream.

ByteArrayResource – wraps a byte array.

9. Template Method Pattern

Classic definition

The abstract superclass defines the algorithm skeleton (order of method calls); subclasses implement specific steps.

Benefits: code reuse and reduced duplication; the superclass handles common steps while subclasses provide custom behavior.

Spring’s usage

Spring combines the template method with callback interfaces. Most extension points (e.g., JDBC, Hibernate integration) follow this pattern.

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 retValue = executeWithStatement(stmt, sql);
            return retValue;
        } catch (SQLException e) {
            // handle exception
        } finally {
            closeStatement(stmt);
            releaseConnection(con);
        }
    }
    protected abstract Object executeWithStatement(Statement stmt, String sql);
}

Because JdbcTemplate is abstract, a callback interface ( StatementCallback) is introduced to supply the variable part:

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

Usage example:

JdbcTemplate jdbcTemplate = ...;
final String sql = ...;
StatementCallback callback = new StatementCallback() {
    public Object doWithStatement(Statement stmt) {
        return ...; // custom logic
    }
};
jdbcTemplate.execute(callback);

The callback isolates changing code while allowing reuse of the stable connection handling provided by JdbcTemplate.

Source: http://blog.csdn.net/caoxiaohong1005

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backend-developmentspringdependency-injectionSingletonFactory Method
ITFLY8 Architecture Home
Written by

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.

0 followers
Reader feedback

How this landed with the community

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.