What you'll learn
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.
@Validon the parameter, plus@NotBlankor@Minon the entity fields. Add a@RestControllerAdviceto 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.
