Quick Answer

Spring Boot autoconfigures a Java web application so you write endpoints rather than plumbing. Annotate a class @RestController, map methods to paths, and let dependency injection supply your service and repository objects.

What Spring Boot removes

Classic Spring required extensive XML or Java configuration before anything ran — a servlet container, a data source, a transaction manager, view resolvers. That configuration was the reputation.

Spring Boot inverts it. It inspects what is on the classpath and configures sensible defaults. Add the web dependency and you get an embedded server on port 8080; add a database driver and JPA and you get a configured data source. You override only what you actually need.

The practical result is a runnable API in about thirty lines. Start a project from the Spring Initializr with Spring Web and Spring Data JPA selected.

A controller

@RestController
@RequestMapping("/api/students")
public class StudentController {

    private final StudentService service;

    public StudentController(StudentService service) {
        this.service = service;
    }

    @GetMapping
    public List<Student> all() {
        return service.findAll();
    }

    @GetMapping("/{id}")
    public Student one(@PathVariable Long id) {
        return service.findById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Student create(@RequestBody @Valid Student s) {
        return service.save(s);
    }
}

@RestController means every method returns data rather than a view name, and Spring converts the returned object to JSON automatically. @RequestMapping sets the shared path prefix. @PathVariable binds the {id} segment; @RequestBody parses the JSON body into an object.

That constructor is doing something important — see dependency injection below.

Dependency injection, which is the core idea

Notice the controller never writes new StudentService(). It declares what it needs in its constructor and Spring supplies it.

Spring maintains a container of objects — beans — created from classes annotated @Service, @Repository, @Component or @RestController. When it builds the controller, it looks for a bean matching each constructor parameter and passes it in.

The reason this matters is testing and swapping implementations. Because the controller depends on a type rather than constructing a specific instance, a test can supply a fake one without touching the controller.

Prefer constructor injection, as above, over @Autowired on fields. It makes dependencies explicit, allows final fields, and lets you construct the class normally in a test.

The three layers

Spring applications conventionally separate concerns:

@Service
public class StudentService {
    private final StudentRepository repo;

    public StudentService(StudentRepository repo) { this.repo = repo; }

    public List<Student> findAll() { return repo.findAll(); }

    public Student findById(Long id) {
        return repo.findById(id)
            .orElseThrow(() -> new StudentNotFoundException(id));
    }
}

public interface StudentRepository extends JpaRepository<Student, Long> {
    List<Student> findByStream(String stream);
}
  • Controller — HTTP only. Parse the request, call the service, return a response.
  • Service — business logic. No HTTP concepts here.
  • Repository — database access.

That repository is an interface with no implementation, and it works. Spring Data generates the implementation at runtime, including findByStream — it parses the method name and writes the query. Method names like findByStreamAndMarksGreaterThan work the same way, which feels like magic the first time.

Things that trip students up

  • Package structure matters. Spring scans for components underneath the main application class's package. A class in a sibling package is not found, and the error — a missing bean — does not obviously say why.
  • Returning entities directly. Convenient, but it exposes your database schema and can leak fields such as password hashes. Real applications return a DTO instead.
  • The N+1 query problem. Fetching 100 students and then accessing each one's course lazily issues 101 queries. Use a fetch join, and check the SQL by enabling spring.jpa.show-sql=true.
  • Validation needs the annotations. @Valid on the parameter, plus @NotBlank or @Min on the entity fields. Add a @RestControllerAdvice to turn validation failures into clean 400 responses rather than stack traces.

Compared with Express, Spring Boot is more verbose and does much more for you. For a student project either is fine; Spring Boot is worth learning because Java backend roles are common in Indian campus hiring.

Frequently Asked Questions

What is the difference between Spring and Spring Boot? Spring is the underlying framework; Spring Boot is a layer that autoconfigures it and embeds a server, removing most of the configuration Spring traditionally required.
What does @RestController do? It marks a class as a web controller whose methods return data rather than view names. Returned objects are converted to JSON automatically.
Why does my repository interface work without an implementation? Spring Data generates the implementation at runtime, deriving queries from the method names. findByStream becomes a query filtering on the stream column.
Should I use field or constructor injection? Constructor injection. It makes dependencies explicit, allows final fields, and lets you instantiate the class directly in tests without a Spring context.
Why is my component not being found? It is probably outside the package tree containing your main application class. Spring scans downwards from there, so classes in sibling packages are not picked up.