Most Java developers can launch a backend with one annotation. Fewer can explain what happens after that annotation disappears.
Deconstructing Spring Boot: Building a Billing Backend with Pure Spring Core
Why I Removed the "Magic"
Spring Boot is excellent for shipping fast. But I wanted to strengthen my backend fundamentals by understanding what Boot normally hides: container bootstrapping, bean wiring, property source handling, and infrastructure setup.
So I built a billing and notification workflow using Spring Core 6.1.4 only. No @SpringBootApplication, no starters, and no auto-configuration.
What I Built
This project demonstrates a production-minded architecture in a small, focused codebase:
- Manual IoC container bootstrapping with
AnnotationConfigApplicationContext - Explicit Java-based configuration for component scanning and property sources
- Custom YAML loader to make
@PropertySourcereadapplication.yml - Manual HikariCP DataSource wiring and
JdbcTemplatesetup - Strategy-style payment routing using
PaymentProcessorinterface + qualifiers - Runtime notification channel swap via setter injection (
EmailSendertoSmsSender) - Schema initialization on startup using
@PostConstruct
Architecture Walkthrough
- Bootstrap layer: Creates the container and executes billing flows
- Config layer: Registers infrastructure beans (
DataSource,JdbcTemplate), loads YAML - Domain service layer: Billing orchestration + notifications
- Processor layer: Pluggable payment and notification implementations
The design goal was simple: keep the business logic independent of concrete providers.
Key Engineering Decisions
- Constructor injection for mandatory dependencies in billing logic
- Setter injection for runtime behavior change in notification strategy
@Qualifierfor deterministic bean resolution when multiple implementations existJdbcTemplatefor concise, safe SQL execution without raw JDBC boilerplate
Example Flow
- Container starts with Java config
- Schema is created if missing
- Billing service processes invoice through selected payment processor
- Successful transaction is persisted to DB
- Notification service sends receipt
- Notification sender is swapped at runtime and second billing run uses new channel
What This Project Is (and Isn’t)
This is a foundational backend architecture project that proves strong understanding of Spring internals and DI mechanics.
It is not presented as a full enterprise product yet (no auth, no distributed tracing, no retry/idempotency pipeline), but it is a solid base to evolve toward that.
What I Learned
- Spring Core gives precise control when you need predictability
- Boot convenience is more valuable after understanding manual wiring
- Interfaces + qualifiers make provider swaps cheap and safe
- Infrastructure ownership (pooling, properties, schema) improves debugging confidence
Next Up
I plan to extend this with transaction boundaries, integration tests, idempotent payment handling, and structured observability to move from architecture demo to production-grade service.