A bean is an object that the Spring IoC container creates, configures, and manages for you, instead of you calling new. Spring finds beans by scanning for stereotype annotations (@Component, @Service, @Repository, @RestController) or by reading @Bean methods in a @Configuration class. It wires them together with dependency injection, so the Controller gets the Service and the Service gets the Repository automatically. It is used for loose coupling, easy testing, a single managed lifecycle, and less boilerplate.
Types
- Stereotype annotations (auto-detected):
@Component(generic),@Service(business logic),@Repository(data access, adds exception translation),@Controller/@RestController(web layer). - Java config beans:
@Configurationwith@Beanmethods, for third-party or hand-built objects. - Scopes:
singleton(default, one per container),prototype(new each time), and web scopesrequest,session,application. - Injection styles: constructor injection (recommended), setter injection, field injection (
@Autowired).
Hands-on Experiment: Creating a Spring Boot application using different environment profiles
The following steps are involved in developing this hands-on experiment.
Step 1: Generate the Project
Step 2: Project Structure
Step 3: pom.xml
Step 4: application.properties
Step 5: Create Entity Class
Step 6: Create Repository Interface
Step 7: Create Service Class
Step 8: Create Controller Class
Step 9: Create Configuration classes
Step 10: Main Application Class
Step 11: Run the Main Application Class
Step 1: Configure the Project on Spring Initializr
Go to start.spring.io and set:
- Project: Maven
- Language: Java
- Spring Boot version: 3.2.x
- Group: com.example
- Artifact: studentbeans
- Name: studentbeans
- Package name: com.example.studentbeans
- Packaging: Jar
- Java: 17
- Dependencies: Spring Web, Spring Data JPA, MySQL Driver
Click Generate to download the ZIP, then extract and import it into your IDE as a Maven project.
Step 2: Generated Project Structure

Step 3: Explore pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>student-beans-demo</artifactId>
<version>1.0.0</version>
<name>student-beans-demo</name>
<description>Spring Beans demo - Controller, Service, Repository</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step 4: application.yml
spring:
application:
name: student-beans-demo
datasource:
url: jdbc:mysql://localhost:3306/student_beans_db?createDatabaseIfNotExist=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
server:
port: 8082
Step 5: Create Entity class
package com.example.studentbeans.entity;
import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank(message = "Name is required")
private String name;
@Email(message = "Invalid email")
@NotBlank(message = "Email is required")
@Column(unique = true)
private String email;
private String course;
public Student() {}
public Student(String name, String email, String course) {
this.name = name;
this.email = email;
this.course = course;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getCourse() { return course; }
public void setCourse(String course) { this.course = course; }
}
Step 6: Create Repository interface
package com.example.studentbeans.repository;
import com.example.studentbeans.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
// @Repository -> Spring registers this as a bean (persistence layer)
@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
List<Student> findByCourse(String course);
boolean existsByEmail(String email);
}
Step 7: Create Service class
package com.example.studentbeans.service;
import com.example.studentbeans.entity.Student;
import com.example.studentbeans.repository.StudentRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.NoSuchElementException;
// @Service -> Spring registers this as a bean (business layer)
@Service
public class StudentService {
private final StudentRepository studentRepository;
// Constructor injection: Spring supplies the StudentRepository bean
public StudentService(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
System.out.println(">>> StudentService bean created, repository injected");
}
public Student create(Student student) {
if (studentRepository.existsByEmail(student.getEmail())) {
throw new IllegalArgumentException("Email already exists: " + student.getEmail());
}
return studentRepository.save(student);
}
public List<Student> findAll() {
return studentRepository.findAll();
}
public List<Student> findByCourse(String course) {
return studentRepository.findByCourse(course);
}
public Student findById(Long id) {
return studentRepository.findById(id)
.orElseThrow(() -> new NoSuchElementException("Student not found with id " + id));
}
public Student update(Long id, Student updated) {
Student existing = findById(id);
existing.setName(updated.getName());
existing.setEmail(updated.getEmail());
existing.setCourse(updated.getCourse());
return studentRepository.save(existing);
}
public void delete(Long id) {
studentRepository.delete(findById(id));
}
}
Step 8: Create Controller Class
package com.example.studentbeans.controller;
import com.example.studentbeans.entity.Student;
import com.example.studentbeans.service.StudentService;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
// @RestController -> Spring registers this as a bean (web layer)
@RestController
@RequestMapping("/api/students")
public class StudentController {
private final StudentService studentService;
// Constructor injection: Spring supplies the StudentService bean
public StudentController(StudentService studentService) {
this.studentService = studentService;
System.out.println(">>> StudentController bean created, service injected");
}
@PostMapping
public ResponseEntity<Student> create(@Valid @RequestBody Student student) {
return ResponseEntity.status(HttpStatus.CREATED).body(studentService.create(student));
}
@GetMapping
public List<Student> getAll(@RequestParam(required = false) String course) {
return (course == null) ? studentService.findAll() : studentService.findByCourse(course);
}
@GetMapping("/{id}")
public Student getById(@PathVariable Long id) {
return studentService.findById(id);
}
@PutMapping("/{id}")
public Student update(@PathVariable Long id, @Valid @RequestBody Student student) {
return studentService.update(id, student);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
studentService.delete(id);
return ResponseEntity.noContent().build();
}
}
Step 9: Create below Configuration classes
package com.example.studentbeans.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
// @Configuration + @Bean -> manually define a bean (useful for third-party classes)
@Configuration
public class BeanConfig {
@Bean
public String appStartedAt() {
return "Student app started at " + LocalDateTime.now();
}
}
package com.example.studentbeans.config;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.Arrays;
// @Component -> generic bean. Prints our beans at startup so you can SEE the container.
@Component
public class BeanInspector implements CommandLineRunner {
private final ApplicationContext context;
public BeanInspector(ApplicationContext context) {
this.context = context;
}
@Override
public void run(String... args) {
System.out.println("===== Application beans in the Spring container =====");
Arrays.stream(context.getBeanDefinitionNames())
.filter(n -> {
Class<?> type = context.getType(n);
return n.equals("appStartedAt")
|| (type != null && type.getName().startsWith("com.example.studentbeans"));
})
.sorted()
.forEach(n -> System.out.println(" -> " + n + " : " + context.getType(n).getSimpleName()));
System.out.println(context.getBean("appStartedAt"));
}
}
package com.example.studentbeans.config;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoSuchElementException.class)
public ResponseEntity<Map<String, String>> notFound(NoSuchElementException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("error", ex.getMessage()));
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<Map<String, String>> badRequest(IllegalArgumentException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("error", ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> validation(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(e -> errors.put(e.getField(), e.getDefaultMessage()));
return ResponseEntity.badRequest().body(errors);
}
}
Step 10: Create MainApplication class
package com.example.studentbeans;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StudentBeansApplication {
public static void main(String[] args) {
SpringApplication.run(StudentBeansApplication.class, args);
}
}
Step 11: Run the StudentBeansApplication


