Spring already encodes the patterns (IoC, proxy, template)
Before this module discusses design patterns in Spring, it has to start with a truth that reframes the whole topic: Spring is itself a giant application of design patterns. More than almost any framework, Spring is the Gang of Four patterns, implemented for you. So the question "what patterns should I use in Spring?" has a surprising first answer — the ones the framework already applies — and a strong warning: do not re-implement, by hand, patterns Spring gives you. This lesson sets that frame, mirroring the honest, anti-over-engineering stance this module takes throughout.
Spring is patterns, all the way down
Look at what you have already used, and name the pattern underneath each:
- Dependency Injection / Inversion of Control — the whole container. You do not construct your collaborators; Spring injects them. This is the Dependency Injection pattern, industrialised.
- Proxy —
@Transactionaland@Asyncwork by wrapping your bean in a proxy that adds behaviour (a transaction, a thread hop) around your method. That is the Proxy pattern; it is why self-invocation bypasses them. - Template Method —
JdbcTemplate,RestTemplate, and the whole "…Template" family define the skeleton of an operation (open connection, do work, handle errors, close) and let you fill in the variable part. That is Template Method. So do the framework's abstract base classes. - Factory — the
ApplicationContextis a bean factory;@Beanmethods are factory methods; Spring creates your objects for you. Factory pattern. - Singleton — the default bean scope is one shared instance — the Singleton pattern, managed by the
container (safely, unlike the hand-rolled
staticsingleton). - Observer —
ApplicationEvents and listeners let beans react to events without direct coupling. The Observer pattern. - Strategy — inject an interface with multiple implementations and choose one; Spring wires the right bean. Strategy pattern.
The list goes on (Decorator, Adapter, Facade all appear). The point: when you use Spring idiomatically, you are already applying a dozen design patterns — through the framework, without writing the pattern code yourself. That is most of what "using patterns in Spring" means.
So do not re-implement what Spring provides
The direct consequence, and the module's recurring warning: do not hand-roll a pattern the framework already gives you. Concretely:
- Do not build your own singleton with
staticand double-checked locking — declare a bean (Spring manages the single instance, thread-safely). - Do not write your own factory to create service objects — the container is the factory; inject them.
- Do not implement your own observer/event bus for in-app events — use
ApplicationEventPublisherand@EventListener. - Do not wrap your own proxy for cross-cutting behaviour — use AOP or the framework's
@Transactional/@Async(the AOP lesson).
Re-implementing these adds code, bugs, and confusion, and fights the framework (the "don't fight the framework" lesson). The idiomatic Spring solution is the pattern, done better than you would do it by hand.
The patterns actually worth choosing
If Spring provides so much, what is left for you to decide? A small set — the patterns that address problems Spring does not solve for you, which this module covers:
- The service layer and its boundaries — where business logic lives and how to structure it as the app grows (the service-boundaries lesson).
- Cross-cutting concerns via AOP — logging, timing, custom transaction-like behaviour applied across many methods without repeating it (the AOP lesson).
- Strategy for pluggable behaviour — an interface with several implementations you choose between (a pricing strategy, a notification channel), wired by Spring.
- Knowing which patterns you do not need — the over-engineering lesson, because the biggest pattern-related risk in Spring is applying too many.
Notice how short this list is. Most structure is already given by the framework; the deliberate pattern choices are few.
The warning this module is built on: do not import the enterprise-Java pattern zoo
The most important point, and one Java especially invites: do not reach for the full "enterprise" pattern
catalogue — elaborate factory hierarchies, abstract-factory-of-factories, a repository interface wrapping
Spring Data (which is already a repository), DTO-assembler-mapper layers, a Manager/Helper/Util for
everything. A great deal of that machinery exists to work around limitations Spring and modern Java do not
have. Spring already gives you DI, proxies, the repository (Spring Data), and clean layering; piling
hand-built patterns on top produces code that is more complex and less idiomatic. As the Django course
put it: most "pattern" code in the wild is a pattern applied where it was not needed. In Spring the risk is
acute because the framework is so pattern-rich that adding more is almost always redundant. Reach for a
pattern only when a real, felt problem in this codebase calls for it, and prefer the plain, idiomatic Spring
solution first — which usually is a pattern the framework already applied.
Check your work
Spring is patterns. DI/IoC (the container), Proxy (@Transactional/@Async), Template Method
(…Template), Factory (the context/@Bean), Singleton (default scope), Observer (events), Strategy
(injected interface) — using Spring idiomatically is applying a dozen patterns, through the framework.
Do not re-implement them. No hand-rolled singletons/factories/observers/proxies — declare beans, inject, use events and AOP. Re-implementing fights the framework and adds bugs.
What is left to choose. The service layer/boundaries, AOP for cross-cutting concerns, Strategy for pluggable behaviour, and knowing which patterns you do not need — a short list.
The warning. Do not import the enterprise-Java pattern zoo (extra factories, a repository over Spring Data, assembler layers) — Spring already provides the patterns; adding more is redundant and less idiomatic. Prefer the plain Spring solution.
Practice
- For each of
@Transactional,JdbcTemplate, theApplicationContext, a singleton bean, and an injected interface, name the Gang of Four pattern it embodies. - Find a hand-rolled singleton (
staticinstance) in code you can access and reason about why a Spring bean is better. - Identify an "enterprise" pattern (a repository interface wrapping Spring Data, an abstract factory) and argue what Spring feature makes it redundant.
- List the handful of patterns actually worth choosing in a Spring app and the problem each solves.
- Take a piece of code you were tempted to "pattern up" and write the plain, idiomatic Spring version; compare.
- Explain, in two sentences, why "using Spring well" already means "using design patterns".
Official documentation
- Spring — Core technologies (IoC container) — DI, factory, singleton, the container.
- Spring — Aspect-oriented programming — Proxies and cross-cutting concerns.
- Refactoring Guru — Design Patterns — The catalogue, to recognise what Spring already provides.
Next: AOP and cross-cutting concerns, without the magic.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship