JVM Advent

The JVM Programming Advent Calendar

How Understanding Request Flow in Spring Boot Changed the Way I Code

When I first stepped into backend development, I believed programming was only about one thing:

“If the output comes, the job is done.”

I bundled everything into one giant file — controllers, logic, database access.I didn’t understand why Spring insisted on layers or why DI, IoC, and annotations were so important. The project structure looked overwhelming, and everything felt abstract.

Everything changed the day I decided to trace my first Spring Boot request and watch how a simple API call traveled through the system. Suddenly, what looked like scattered pieces turned into a well-designed, meaningful architecture. It didn’t just teach me Spring Boot — it changed the way I think about writing software.


What I Used to Think Backend Development Was

In the beginning, this was my reality:

  • All classes dumped into one package
  • Endless, congested code inside one file
  • No idea what executes, what doesn’t, or why
  • Maven structure felt unnecessary
  • Layers didn’t make sense
  • Annotations were intimidating
  • No understanding of why Service existed between Controller and Repository

It was like trying to build a house without knowing what bricks, beams, or foundations were.


The Turning Point: Tracing My First Request

One day, I opened my console logs and started following the journey of an incoming request:

  • It first hit the Controller
  • Then passed into the Service
  • Then reached the Repository
  • Finally touched the Database
  • And then returned the response through the same layers

That visual flow — even just in the logs — changed everything for me.

I realized:

  • DI reduces tight coupling
  • IoC manages object lifecycles so you don’t
  • Layers exist to protect and organize the system
  • Spring Boot is powerful because of its structure, not despite it

Architecture became a living system, not a theory.


Controller → Service → Repository: The Flow That Made Everything Click

Controller — The Entry Point

The controller receives the request, interacts with the service, and returns the appropriate response or view.

@Controller
@RequestMapping("/employees")
public class EmployeeController {

    private EmployeeService employeeService;

    public EmployeeController(EmployeeService theEmployeeService) {
        employeeService = theEmployeeService;
    }

    @GetMapping("/list")
    public String listEmployees(Model theModel) {
        List<Employee> theEmployees = employeeService.findAll();
        theModel.addAttribute("employees", theEmployees);
        return "employees/list-employees";
    }
}


Controllers should be small and focused — no business logic inside them.


Service — The Logic Layer

This is where business decisions happen. It protects the repository from being accessed directly.

public interface EmployeeService {
    List<Employee> findAll();
    Employee findById(int theId);
    void save(Employee theEmployee);
    void deleteById(int theId);
    boolean existsByEmailId(Employee theEmployee);
}


Implementation:

@Service
public class EmployeeServiceImpl implements EmployeeService {

    private EmployeeRepository employeeRepository;

    @Autowired
    public EmployeeServiceImpl(EmployeeRepository theEmployeeRepository) {
        employeeRepository = theEmployeeRepository;
    }

    @Override
    public List<Employee> findAll() {
        return employeeRepository.findAllByOrderByLastNameAsc();
    }
}


The service layer keeps your application clean, secure, and maintainable.


Repository — Where Database Interactions Happen

With Spring Data JPA, repositories become incredibly simple:

public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
    boolean existsByEmail(String email);
    List<Employee> findAllByOrderByLastNameAsc();
}

The framework generates most queries automatically.


Entity — Mapping Java Objects to Database Tables

Entities act as a bridge between the database and your Java application.

@Entity
@Table(name="employee")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @NotBlank
    private String firstName;

    @NotBlank
    private String lastName;

    @NotBlank
    private String email;

    // constructors, getters, setters
}

Spring (plus Jackson) takes care of converting between JSON ↔ Java ↔ Database.


When MVC Finally Made Sense

Moving into full MVC with Thymeleaf gave me clarity:

  • Controllers handle the request
  • Services handle business logic
  • Repositories handle persistence
  • Templates display the data

The project structure stopped looking like a burden and became something I respected. The flow felt natural and powerful.


A Simple CRUD Example That Made It Real

The moment everything clicked was when I saw this flow in my own CRUD app:

  • Client hits GET /employees/list
  • Controller asks Service for data
  • Service queries the Repository
  • Repository returns data from the database
  • Controller adds data to Model
  • Thymeleaf displays it on the page

Suddenly the architecture wasn’t an academic concept — it was working in front of me.

Here is the GitHub repository of the CRUD app I used in this article:

👉 **https://github.com/MAffanG/employee-crud-api**


What This Taught Me About Coding

Understanding the request flow transformed everything about my approach:

  • I no longer chase outputs — I chase clarity
  • I think in terms of architecture, not hacks
  • Debugging became easier and faster
  • My code became cleaner and more intentional
  • I finally felt like a backend developer, not someone just trying things until they work

This experience didn’t just teach me Spring Boot — it changed the way I respect software design as a whole.

Next Post

Previous Post

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2025 JVM Advent | Powered by steinhauer.software Logosteinhauer.software

Theme by Anders Norén