Real World Example

How Spring Finds Your Controllers

When a Spring Boot app starts, it scans packages for classes annotated with @Component/@RestController, creates them with reflection, then maps each @GetMapping method to a URL. Here is a tiny version of that idea.

Example

A mini router: scans a class for @Get methods, registers them in a map, and dispatches "requests" by path.

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Map<String, Method> routes = new TreeMap<>();
        Object controller = ProductController.class.getDeclaredConstructor().newInstance();

        for (Method m : ProductController.class.getDeclaredMethods()) {
            Get get = m.getAnnotation(Get.class);
            if (get != null) routes.put(get.value(), m);
        }
        System.out.println("Mapped routes: " + routes.keySet());

        for (String path : List.of("/products", "/health", "/unknown")) {
            Method handler = routes.get(path);
            String response = handler == null ? "404 Not Found" : "200 " + handler.invoke(controller);
            System.out.println("GET " + path + " -> " + response);
        }
    }
}

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface Get { String value(); }

class ProductController {
    @Get("/products") public String list() { return "[Phone, Laptop, Watch]"; }
    @Get("/health") public String health() { return "{status: UP}"; }
    public String notAnEndpoint() { return "hidden"; }
}

Output

Mapped routes: [/health, /products]
GET /products -> 200 [Phone, Laptop, Watch]
GET /health -> 200 {status: UP}
GET /unknown -> 404 Not Found

The Real Thing

@RestController
@RequestMapping("/api/products")
public class ProductController {
    private final ProductService service;
    public ProductController(ProductService service) { this.service = service; }  // injected via reflection

    @GetMapping("/{id}")
    public ProductDto get(@PathVariable Long id) { return service.get(id); }
}